home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume26 / xc-4.1 / part02 < prev    next >
Encoding:
Text File  |  1993-04-13  |  66.2 KB  |  3,328 lines

  1. Newsgroups: comp.sources.unix
  2. From: jpr@jpr.com (Jean-Pierre Radley)
  3. Subject: v26i151: xc-4.1 - a serial communications program, V4.1, Part02/03
  4. Sender: unix-sources-moderator@vix.com
  5. Approved: paul@vix.com
  6.  
  7. Submitted-By: jpr@jpr.com (Jean-Pierre Radley)
  8. Posting-Number: Volume 26, Issue 151
  9. Archive-Name: xc-4.1/part02
  10.  
  11. #! /bin/sh
  12. # This is a shell archive.  Remove anything before this line, then unpack
  13. # it by saving it into a file and typing "sh file".  To overwrite existing
  14. # files, type "sh file -c".  You can also feed this as standard input via
  15. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  16. # will see the following message at the end:
  17. #        "End of archive 2 (of 3)."
  18. # Contents:  xcb+.c xcmain.c xcport.c xcxmdm.c
  19. # Wrapped by vixie@gw.home.vix.com on Wed Apr 14 00:22:46 1993
  20. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  21. if test -f 'xcb+.c' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'xcb+.c'\"
  23. else
  24. echo shar: Extracting \"'xcb+.c'\" \(22715 characters\)
  25. sed "s/^X//" >'xcb+.c' <<'END_OF_FILE'
  26. X/*    xcb+.c -- CIS B+ Protocol module for XC
  27. X    This file uses 4-character tabstops
  28. X */
  29. X
  30. X#include <stdio.h>
  31. X#include <string.h>
  32. X#include <sys/types.h>
  33. X#include <sys/stat.h>
  34. X#include <signal.h>
  35. X#include <time.h>
  36. X#include <fcntl.h>
  37. X#include <ctype.h>
  38. X#define NODEBUG 1    /* prevents xc.h from defining DEBUG */
  39. X#include "xc.h"
  40. X
  41. X#define min(x,y)    ((int)(x)<(int)(y)?(x):(y))
  42. X#define max(x,y)    ((int)(x)>(int)(y)?(x):(y))
  43. X#define MaskLowRange 0x01
  44. X#define MaskHiRange 0x10
  45. X#define Send_Ahead_Buffers    5
  46. X
  47. enum {
  48. X    Check_B,
  49. X    Check_CRC
  50. X    } ;
  51. X
  52. enum {
  53. X    Quote_Default,
  54. X    Quote_Not_NULL,
  55. X    Quote_Extended,
  56. X    Quote_Full,
  57. X    Quote_Mask
  58. X    } ;
  59. X
  60. enum {
  61. X    Overwrite,
  62. X    Resume
  63. X    } ;
  64. X
  65. enum {
  66. X    Resume_Allowed,
  67. X    Resume_Not_Allowed,
  68. X    Resume_Failed,
  69. X    Resume_Denied
  70. X    } ;
  71. X
  72. typedef enum {
  73. X    S_Get_DLE,
  74. X    S_DLE_Seen,
  75. X    S_DLE_B_Seen,
  76. X    S_Get_Data,
  77. X    S_Get_check,
  78. X    S_Get_CRC,
  79. X    S_Verify_CRC,
  80. X    S_VErify_CKS,
  81. X    S_VerIfy_Packet,
  82. X    S_Send_NAK,
  83. X    S_SenD_ACK,
  84. X    S_SEnd_ENQ,
  85. X    S_Resend_Packets,
  86. X} Sender_Action;
  87. X
  88. extern short cr_add;
  89. extern void cl_line();
  90. static char S_Buffer[1033], R_Buffer[1033], tdir[32];
  91. char    Name[SM_BUFF];
  92. static unchar Mask[32];
  93. static unsigned Checksum;
  94. static    Ch,                /* last char read from remote */
  95. X        Quoting,        /* quoting level requested by the user */
  96. X        Window_Size,    /* Send size of send ahead window */
  97. X        PackeT_Size,    /* Maximum block size. */
  98. X        R_BUffer_Len, S_Bytes, R_Bytes, Seq_Num, PendinG_Count,
  99. X        Next_Packet, Packets_Btwn_ACKs, Last_ACK, textmode, Last_Chr,
  100. X        Send_Errors, Read_Errors;
  101. static short Max_Errors=10, Abort_Flag, Not_Masked, Sent_ENQ, Actual_Check,
  102. X            Valid_To_Resume_Download, ValiD_To_Resume_Upload,
  103. X            Send_FIle_Information, Packet_Received, Result;
  104. static FILE *Data_File;
  105. static long    already_have, data, total_read, total_sent,
  106. X            fsize, start, carriage_return;
  107. X
  108. struct {
  109. X    int Seq;
  110. X    int PackeT_Size;
  111. X    char *packet;
  112. X} Pending[Send_Ahead_Buffers];
  113. X
  114. extern ushort crc_xmodem_tab[256];
  115. X
  116. static void
  117. init_check()
  118. X{
  119. X    Checksum=Actual_Check ? 0xffff : 0;
  120. X}
  121. X
  122. static void
  123. do_checksum(ch)
  124. unsigned ch;
  125. X{
  126. X    if (Actual_Check==Check_B){
  127. X        Checksum<<=1;
  128. X        if (Checksum>255)
  129. X            Checksum=(Checksum&0xFF)+1;
  130. X        Checksum+=ch&0xFF;
  131. X        if (Checksum>255)
  132. X            Checksum=(Checksum&0xFF)+1;
  133. X    } else
  134. X    Checksum=(crc_xmodem_tab[((Checksum>>8)^ch)&0xff]^(Checksum<<8))&0xffff;
  135. X}
  136. X
  137. X/* #define CIS_DEBUG /* for B+ logging */
  138. X
  139. X#ifdef CIS_DEBUG
  140. static FILE *bfp = NIL(FILE);
  141. static void
  142. xclog(dir, val)
  143. char dir;
  144. int val;
  145. X{
  146. X    static int cnt, lastdir;
  147. X
  148. X    if (!bfp)
  149. X        bfp=fopen("xc.log","w"),
  150. X        cnt=0,
  151. X        lastdir=dir;
  152. X
  153. X    if (++cnt>20||lastdir!=dir)
  154. X        fputc('\n',bfp),
  155. X        cnt=1;
  156. X
  157. X    if (lastdir!=dir)
  158. X        fputc('\n',bfp);
  159. X
  160. X    if (val>'~'||val<' ')
  161. X        fprintf(bfp,"%c%1x%1x ",dir,val/16,val%16);
  162. X    else
  163. X        fprintf(bfp,"%c%c  ",dir,val);
  164. X
  165. X    lastdir=dir;
  166. X}
  167. X
  168. static void
  169. Why_NAK(reason)
  170. char *reason;
  171. X{
  172. X    sprintf(Msg,"Sending NAK, %s",reason);
  173. X    S0(Msg);
  174. X}
  175. X
  176. X#else
  177. X#define xclog(dir,val)
  178. X#define Why_NAK(reason)
  179. X#endif
  180. X
  181. static void
  182. stats(count)
  183. int count;
  184. X{
  185. X    int rate, minutes, sec, data_percent, rate_percent;
  186. X    long chars, elapsed, now, rem;
  187. X
  188. X    data+=count;
  189. X
  190. X    if (!fsize)
  191. X        data_percent=0;
  192. X    else
  193. X        data_percent=100*(data+carriage_return)/fsize;
  194. X
  195. X    if (data_percent>100)
  196. X        data_percent=100;
  197. X
  198. X    time(&now);
  199. X
  200. X    elapsed=now-start;
  201. X    chars=data+carriage_return-already_have-(tdir[0]=='T'?PackeT_Size-1:0);
  202. X    if (elapsed<5 || !chars)
  203. X        ttgoto(LI-6,26),
  204. X        fputs("estimating",tfp);
  205. X    else
  206. X        rate=chars/elapsed,
  207. X        rem=(fsize-(data+carriage_return-already_have))/rate,
  208. X        minutes=rem/60,
  209. X        sec=rem%60,
  210. X        rate_percent=1000*rate/mrate(NIL(char)),
  211. X
  212. X        ttgoto(LI-6,26),
  213. X        fprintf(tfp,"%8.1d:%2.2d",minutes,sec),
  214. X
  215. X        minutes=elapsed/60,
  216. X        sec=elapsed%60,
  217. X        ttgoto(LI-6,61),
  218. X        fprintf(tfp,"%8.1d:%2.2d",minutes,sec),
  219. X
  220. X        ttgoto(LI-4,23),
  221. X        fprintf(tfp,"Rate: %d characters per second ", rate,rate_percent);
  222. X
  223. X    ttgoto(LI-8,0),
  224. X    fprintf(tfp,"%8.1ld",total_sent),
  225. X    ttgoto(LI-8,20),
  226. X    fprintf(tfp,"%8.1ld",total_read),
  227. X    ttgoto(LI-8,40);
  228. X    if (!data_percent)
  229. X        fprintf(tfp,"%8.1ld",data);
  230. X    else
  231. X        fprintf(tfp,"%8.1ld %3.1u %%",data,data_percent);
  232. X    if (carriage_return)
  233. X        ttgoto(LI-8,60),
  234. X        fprintf(tfp,"%+7.1ld",carriage_return);
  235. X}
  236. X
  237. static void
  238. showmode()
  239. X{
  240. X    int l;
  241. X    sprintf(Msg,"%s %s (%ld bytes) as %s",tdir,Name,fsize,
  242. X        textmode?"ASCII":"BINARY");
  243. X
  244. X    ttgoto(LI-12,0);
  245. X    cl_line();
  246. X    if ((l=strlen(Msg)) < CO)
  247. X        ttgoto(LI-12,(CO-l)/2 -1);
  248. X    fputs(Msg,tfp);
  249. X
  250. X    time(&start);
  251. X}
  252. X
  253. static void
  254. Discard_ACKed_Packets()
  255. X{
  256. X    int i, n;
  257. X    short Packet_Acked=FALSE;
  258. X
  259. X    Last_ACK=Ch;
  260. X    n=(Next_Packet+PendinG_Count)%Send_Ahead_Buffers;
  261. X
  262. X    for (i=PendinG_Count;i>0;i--){
  263. X        n--;
  264. X        if (n<0)
  265. X            n+=5;
  266. X
  267. X        if (Pending[n].Seq==Ch-'0')
  268. X            Packet_Acked=TRUE,
  269. X            Next_Packet=(n+1)%Send_Ahead_Buffers;
  270. X
  271. X        if (Packet_Acked==TRUE)
  272. X            free(Pending[n].packet),
  273. X            Pending[n].packet=NIL(char),
  274. X            PendinG_Count--;
  275. X    }
  276. X}
  277. X
  278. static void
  279. Send_Byte(ch)
  280. int ch;
  281. X{
  282. X    sendbyte(ch);
  283. X    total_sent++;
  284. X    xclog('>',ch);
  285. X}
  286. X
  287. static void
  288. Send_Masked_Byte(ch)
  289. int ch;
  290. X{
  291. X    if (ch<0x20){
  292. X        if (Quoting==Quote_Full||(Mask[ch]&MaskLowRange))
  293. X            Send_Byte(DLE),
  294. X            ch+='@';
  295. X    } else if (ch>=0x80&&ch<0xA0&&
  296. X        (Quoting==Quote_Full||(Mask[ch-0x80]&MaskHiRange)))
  297. X            Send_Byte(DLE),
  298. X            ch=ch+'`'-0x80;
  299. X
  300. X    Send_Byte(ch);
  301. X}
  302. X
  303. static
  304. Read_Byte()
  305. X{
  306. X    if ((Ch=readbyte(10))== -1)
  307. X        return FAILURE;
  308. X    total_read++;
  309. X    xclog('<',Ch);
  310. X    return SUCCESS;
  311. X}
  312. X
  313. static
  314. Read_Masked_Byte()
  315. X{
  316. X    Not_Masked=TRUE;
  317. X
  318. X    if (!Read_Byte())
  319. X        return FAILURE;
  320. X
  321. X    if (Ch==DLE){
  322. X        if (!Read_Byte())
  323. X            return FAILURE;
  324. X
  325. X        Not_Masked=FALSE;
  326. X
  327. X        if (Ch>='`')
  328. X            Ch+=0x80;
  329. X
  330. X        Ch&=0x9F;
  331. X    }
  332. X    return SUCCESS;
  333. X}
  334. X
  335. static void
  336. Send_ACK()
  337. X{
  338. X    Send_Byte(DLE);
  339. X    Send_Byte(Seq_Num+'0');
  340. X}
  341. X
  342. static void
  343. Init()
  344. X{
  345. X    int i;
  346. X
  347. X    R_BUffer_Len=Window_Size=PendinG_Count=Next_Packet=
  348. X        R_Bytes=S_Bytes=Seq_Num=Packets_Btwn_ACKs=Last_ACK=0;
  349. X
  350. X/*    PackeT_Size=(mrate(NIL(char))) > 1200 ? 1025 : 513; */
  351. X    i=mrate(NIL(char));
  352. X    PackeT_Size=(i>2400) ? 2049 : (i>1200) ? 1025 : 513;
  353. X
  354. X    Quoting=Quote_Mask;
  355. X
  356. X    for (i=0;i<Send_Ahead_Buffers;i++)
  357. X        Pending[i].packet=NIL(char);
  358. X
  359. X    Actual_Check=Check_B;
  360. X    Abort_Flag=Sent_ENQ=FALSE;
  361. X
  362. X    memset(Mask,0,32);
  363. X
  364. X    Mask[ETX]=Mask[ENQ]=Mask[DLE]=Mask[NAK]=Mask[XON]=Mask[XOFF]=MaskLowRange;
  365. X
  366. X    total_sent=total_read=data=fsize=Read_Errors=Send_Errors=
  367. X        already_have=carriage_return=0;
  368. X    fputs("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",tfp);
  369. X    ttgoto(LI-14,25);
  370. X    S1("CIS B-Plus Protocol Transfer");
  371. X
  372. X    ttgoto(LI-10,0);
  373. X    fputs("B+ Bytes Sent       B+ Bytes Rcvd",tfp);
  374. X    ttgoto(LI-10,40);
  375. X    fputs("Data Bytes          Carriage Returns",tfp);
  376. X    ttgoto(LI-6,10);
  377. X    fputs("Time Remaining:",tfp);
  378. X    ttgoto(LI-6,48);
  379. X    fputs("Elapsed Time:",tfp);
  380. X}
  381. X
  382. static void
  383. XXmit_Packet(Size, Seq, Packet)
  384. int Size, Seq;
  385. unchar *Packet;
  386. X{
  387. X    register I;
  388. X
  389. X    init_check();
  390. X    Send_Byte(DLE);
  391. X    Send_Byte('B');
  392. X    Send_Byte(Seq+'0');
  393. X    do_checksum(Seq+'0');
  394. X
  395. X    for (I=0;I<Size;I++)
  396. X        Send_Masked_Byte(Packet[I]),
  397. X        do_checksum(Packet[I]);
  398. X
  399. X    Send_Byte(ETX);
  400. X    do_checksum(ETX);
  401. X    if (Actual_Check==Check_B)
  402. X        Send_Masked_Byte(Checksum);
  403. X    else
  404. X        Send_Masked_Byte(Checksum>>8),
  405. X        Send_Masked_Byte(Checksum&0xff);
  406. X}
  407. X
  408. static
  409. Wait_For_ACK(Have_DLE_B, Acknowledge, Resend)
  410. short Have_DLE_B, Acknowledge, Resend;
  411. X{
  412. X    Sender_Action Action;
  413. X
  414. X    int i=0, n, RCV_Num, Errors=0;
  415. X
  416. X    R_BUffer_Len=0;
  417. X    Packet_Received=FALSE;
  418. X
  419. X    if (Have_DLE_B)
  420. X        Action=S_DLE_B_Seen;
  421. X    else
  422. X        Action=S_Get_DLE;
  423. X
  424. X    while (Errors<Max_Errors)
  425. X        switch (Action){
  426. X        case S_Get_Data:
  427. X            if (Read_Masked_Byte()==FAILURE){
  428. X                Action=S_Send_NAK;
  429. X                Why_NAK("couldn't read next data byte");
  430. X            } else if (Not_Masked && Ch==ETX)
  431. X                Action=S_Get_check;
  432. X            else if (Not_Masked && Ch==ENQ)
  433. X                Action=S_SenD_ACK;
  434. X            else if (i==PackeT_Size){
  435. X                Action=S_Send_NAK;
  436. X                Why_NAK("incoming buffer overflow");
  437. X            } else
  438. X                R_Buffer[i++]=Ch,
  439. X                do_checksum(Ch);
  440. X            break;
  441. X
  442. X        case S_Get_DLE:
  443. X            if (Packets_Btwn_ACKs>Window_Size+2&&PendinG_Count){
  444. X                Packets_Btwn_ACKs=0;
  445. X                Action=S_SEnd_ENQ;
  446. X                continue;
  447. X            }
  448. X            if (!Read_Byte())
  449. X                Action=S_SEnd_ENQ;
  450. X            else if (Ch==DLE)
  451. X                Action=S_DLE_Seen;
  452. X            else if (Ch==NAK)
  453. X                Action=S_SEnd_ENQ;
  454. X            else if (Ch==ENQ)
  455. X                Action=S_SenD_ACK;
  456. X            else if (Ch==ETX){
  457. X                Action=S_Send_NAK;
  458. X                Why_NAK("awaiting DLE, got ETX");
  459. X            }
  460. X            break;
  461. X
  462. X        case S_DLE_Seen:
  463. X            if (!Read_Byte())
  464. X                Action=S_SEnd_ENQ;
  465. X            else if (Ch>='0'&&Ch<='9')
  466. X                if (Sent_ENQ&&Ch==Last_ACK){
  467. X                    Sent_ENQ=FALSE;
  468. X
  469. X                    if (!PendinG_Count)
  470. X                        return SUCCESS;
  471. X                    else
  472. X                        Action=S_Resend_Packets;
  473. X                } else {
  474. X                    Discard_ACKed_Packets();
  475. X                    if (Sent_ENQ)
  476. X                        Action=S_Get_DLE;
  477. X                    else
  478. X                        return SUCCESS;
  479. X                }
  480. X            else if (Ch==';')
  481. X                Action=S_Get_DLE;
  482. X            else if (Ch=='B')
  483. X                Action=S_DLE_B_Seen;
  484. X            else if (Ch==ENQ)
  485. X                Action=S_SenD_ACK;
  486. X            else
  487. X                Action=S_Get_DLE;
  488. X            break;
  489. X
  490. X        case S_DLE_B_Seen:
  491. X            if (!Read_Byte()){
  492. X                Action=S_Send_NAK;
  493. X                Why_NAK("no data byte after DLE-B");
  494. X            } else if (Ch==ENQ)
  495. X                Action=S_SenD_ACK;
  496. X            else {
  497. X                init_check();
  498. X                RCV_Num=Ch-'0';
  499. X                do_checksum(Ch);
  500. X                i=0;
  501. X                Action=S_Get_Data;
  502. X            }
  503. X            break;
  504. X
  505. X        case S_Get_check:
  506. X            do_checksum(ETX);
  507. X
  508. X            if (Read_Masked_Byte()==FAILURE){
  509. X                Action=S_Send_NAK;
  510. X                Why_NAK("no incoming checksum");
  511. X            } else if (Not_Masked&&Ch==ENQ)
  512. X                Action=S_SenD_ACK;
  513. X            else if (Actual_Check==Check_CRC)
  514. X                Action=S_Get_CRC;
  515. X            else
  516. X                Action=S_VErify_CKS;
  517. X            break;
  518. X
  519. X        case S_Get_CRC:
  520. X            do_checksum(Ch);
  521. X
  522. X            if (Read_Masked_Byte()==FAILURE){
  523. X                Action=S_Send_NAK;
  524. X                Why_NAK("no incoming CRC value");
  525. X            } else if (Not_Masked&&Ch==ENQ)
  526. X                Action=S_SenD_ACK;
  527. X            else
  528. X                Action=S_Verify_CRC;
  529. X            break;
  530. X
  531. X        case S_Verify_CRC:
  532. X            do_checksum(Ch);
  533. X
  534. X            if (!Checksum)
  535. X                Action=S_VerIfy_Packet;
  536. X            else {
  537. X                Action=S_Send_NAK;
  538. X                Why_NAK("CRC error");
  539. X            }
  540. X            break;
  541. X
  542. X        case S_VErify_CKS:
  543. X            if (Checksum==Ch)
  544. X                Action=S_VerIfy_Packet;
  545. X            else {
  546. X                Action=S_Send_NAK;
  547. X                Why_NAK("Checksum error");
  548. X            }
  549. X            break;
  550. X
  551. X        case S_VerIfy_Packet:
  552. X            if (RCV_Num==((Seq_Num+1)%10)||R_Buffer[0]=='F'){
  553. X                Packets_Btwn_ACKs++;
  554. X                Seq_Num=RCV_Num;
  555. X                if (Acknowledge)
  556. X                    Send_ACK();
  557. X                R_BUffer_Len=i;
  558. X                Packet_Received=TRUE;
  559. X                return FAILURE;
  560. X            } else if (RCV_Num==Seq_Num)
  561. X                Action=S_SenD_ACK;
  562. X            else {
  563. X                Action=S_Send_NAK;
  564. X                Why_NAK("packet out of sequence");
  565. X            }
  566. X            break;
  567. X
  568. X        case S_Send_NAK:
  569. X            ttgoto(LI-2,20);
  570. X            sprintf(Msg,"Read Errors: %2.1d",++Read_Errors);
  571. X            S;
  572. X            Errors++;
  573. X            Send_Byte(NAK);
  574. X            Action=S_Get_DLE;
  575. X            break;
  576. X
  577. X        case S_SenD_ACK:
  578. X            Send_ACK();
  579. X            Action=S_Get_DLE;
  580. X            break;
  581. X
  582. X        case S_SEnd_ENQ:
  583. X            ttgoto(LI-2,40);
  584. X            sprintf(Msg,"Send Errors: %2.1d",++Send_Errors);
  585. X            S;
  586. X            Errors++;
  587. X            Sent_ENQ=TRUE;
  588. X            Send_Byte(ENQ);
  589. X            Send_Byte(ENQ);
  590. X            Action=S_Get_DLE;
  591. X            break;
  592. X
  593. X        case S_Resend_Packets:
  594. X            if (Resend)
  595. X                for (i=0;i<PendinG_Count;i++)
  596. X                    n=(Next_Packet+i)%Send_Ahead_Buffers,
  597. X                    Xmit_Packet(
  598. X                        Pending[n].PackeT_Size,
  599. X                        Pending[n].Seq,
  600. X                        Pending[n].packet);
  601. X            else
  602. X                return FAILURE;
  603. X
  604. X            Action=S_Get_DLE;
  605. X            break;
  606. X        }
  607. X    return FAILURE;
  608. X}
  609. X
  610. static void
  611. Send_Failure(Code, Text)
  612. char Code;
  613. char *Text;
  614. X{
  615. X    int Len, Seq;
  616. X
  617. X    S_Buffer[0]='F';
  618. X    S_Buffer[1]=Code;
  619. X    Len=2;
  620. X    while (*Text)
  621. X        S_Buffer[Len++]= *Text++;
  622. X
  623. X    Seq=(Seq_Num+1)%10;
  624. X
  625. X    while (PendinG_Count&&Wait_For_ACK(FALSE,FALSE,FALSE))
  626. X        ;
  627. X
  628. X    Xmit_Packet(Len,Seq,S_Buffer);
  629. X
  630. X    do
  631. X        Wait_For_ACK(FALSE,FALSE,FALSE);
  632. X    while (Packet_Received);
  633. X}
  634. X
  635. static
  636. XFlush_Pending()
  637. X{
  638. X    while (PendinG_Count)
  639. X        if (!Wait_For_ACK(FALSE,TRUE,TRUE))
  640. X            return FAILURE;
  641. X
  642. X    return SUCCESS;
  643. X}
  644. X
  645. static void
  646. Send_Abort()
  647. X{
  648. X    fclose(Data_File);
  649. X    sprintf(Msg,"Transfer abort requested");
  650. X    S0(Msg);
  651. X    Send_Failure('A',Msg);
  652. X}
  653. X
  654. static
  655. Send_Packet(Size)
  656. int Size;
  657. X{
  658. X    int Next, Next_Seq;
  659. X
  660. X    while ((PendinG_Count>Window_Size))
  661. X        if (!Wait_For_ACK(FALSE,TRUE,TRUE)){
  662. X            Send_Abort();
  663. X            return FAILURE;
  664. X        }
  665. X
  666. X    Next=(Next_Packet+PendinG_Count)%Send_Ahead_Buffers;
  667. X    PendinG_Count++;
  668. X
  669. X    Next_Seq=Seq_Num=(Seq_Num+1)%10;
  670. X    Pending[Next].Seq=Next_Seq;
  671. X    Pending[Next].packet=strdup(S_Buffer);
  672. X    Pending[Next].PackeT_Size=Size;
  673. X    Packets_Btwn_ACKs=0;
  674. X
  675. X    Xmit_Packet(Size,Next_Seq,S_Buffer);
  676. X
  677. X    return SUCCESS;
  678. X}
  679. X
  680. static ulong
  681. cnvAtoL(ptr)
  682. char *ptr;
  683. X{
  684. X    ushort sign=FALSE;
  685. X    char ch;
  686. X    ulong result=0;
  687. X
  688. X    ch= *ptr++;
  689. X
  690. X    if (ch=='-')
  691. X        sign=TRUE,
  692. X        ch= *ptr++;
  693. X
  694. X    while (ch>='0'&&ch<='9')
  695. X        result=result*10+(ch-'0'),
  696. X        ch= *ptr++;
  697. X
  698. X    return(sign?-result:result);
  699. X}
  700. X
  701. static
  702. char *cnvLtoA(ptr, n)
  703. char *ptr;
  704. ulong n;
  705. X{
  706. X    char tmp1[11], *tmp2=tmp1;
  707. X
  708. X    if (!n){
  709. X        *ptr++ ='0';
  710. X        return ptr;
  711. X    }
  712. X
  713. X    *tmp2++ =0;
  714. X    do 
  715. X        *tmp2++ =((char)(n%10))+'0',
  716. X        n/=10;
  717. X    while (n>0);
  718. X
  719. X    tmp2--;
  720. X    while (*tmp2)
  721. X        *ptr++ = *tmp2--;
  722. X
  723. X    return ptr;
  724. X}
  725. X
  726. static void
  727. Send_Unexpected_Packet()
  728. X{
  729. X    sprintf(Msg,"Unexpected packet type");
  730. X    S0(Msg);
  731. X    Send_Failure('N',Msg);
  732. X}
  733. X
  734. XFILE *
  735. QueryCreate(Offer_Resume)
  736. short Offer_Resume;
  737. X{
  738. X    int key;
  739. X    short Condition;
  740. X    FILE *fileptr;
  741. X
  742. X    Condition = isregfile(Name) ? Offer_Resume : Resume_Denied;
  743. X
  744. X    if (access(Name,0)&&(fileptr=fopen(Name,"w"))){
  745. X        Result=Overwrite;
  746. X        return fileptr;
  747. X    } else if (access(Name,2))
  748. X        Condition = Resume_Denied;
  749. X
  750. X    switch(Condition){
  751. X    case Resume_Allowed:
  752. X        sprintf(Msg,"'%s' exists; Overwrite, Resume, reName, or Abort?",Name);
  753. X        break;
  754. X
  755. X    case Resume_Not_Allowed:
  756. X        sprintf(Msg,"'%s' exists; Overwrite, reName, or Abort?",Name);
  757. X        break;
  758. X
  759. X    case Resume_Failed:
  760. X        sprintf(Msg,"'%s' CRC error; Overwrite, reName or Abort?",Name);
  761. X        break;
  762. X
  763. X    case Resume_Denied:
  764. X        sprintf(Msg,"Permission denied for '%s'; reName, or Abort?",Name);
  765. X        break;
  766. X    }
  767. X    if (cismode)
  768. X        S0(Msg);
  769. X    else
  770. X        S2(Msg);
  771. X
  772. X    for (;;){
  773. X        beep();
  774. X        key=toupper(fgetc(stdin));
  775. X        if (isupper(key)){
  776. X            fputc(key,tfp);
  777. X
  778. X            switch(key){
  779. X            case 'O':
  780. X                if (Condition!=Resume_Denied){
  781. X                    Result=Overwrite;
  782. X                    return fopen(Name,"w");
  783. X                }
  784. X                break;
  785. X
  786. X            case 'N':
  787. X                fputc('\r',tfp);
  788. X                cl_line();
  789. X                show(-1,"Enter New Name:");
  790. X                getline();
  791. X                getword();
  792. X                strcpy(Name,word);
  793. X                return QueryCreate(Offer_Resume);
  794. X
  795. X            case 'A':
  796. X                return NIL(FILE);
  797. X
  798. X            case 'R':
  799. X                if (Condition==Resume_Allowed){
  800. X                    Result=Resume;
  801. X                    return fopen(Name,"r+");
  802. X                }
  803. X                break;
  804. X            }
  805. X            fputc('\b',tfp);
  806. X        }
  807. X    }
  808. X}
  809. X
  810. static
  811. Read(fp, buf, want)
  812. XFILE *fp;
  813. char *buf;
  814. register int want;
  815. X{
  816. X    register c;
  817. X    int read=0;
  818. X
  819. X    while (want--)
  820. X        switch(c=getc(fp)){
  821. X        case EOF:
  822. X            return read;
  823. X
  824. X        case '\n':
  825. X            if (cr_add&&textmode&&Last_Chr!='\r')
  826. X                ungetc(c,fp),
  827. X                carriage_return++,
  828. X                c='\r';
  829. X
  830. X        default:
  831. X            Last_Chr= *buf++ =c;
  832. X            read++;
  833. X        }
  834. X
  835. X    return read;
  836. X}
  837. X
  838. static
  839. Write(fp, buf, want)
  840. XFILE *fp;
  841. char *buf;
  842. register int want;
  843. X{
  844. X    int written=0;
  845. X
  846. X    for (;want-->0;buf++){
  847. X        if (textmode){
  848. X            if (*buf=='\r'){
  849. X                Last_Chr= *buf;
  850. X                continue;
  851. X            }
  852. X            if (Last_Chr=='\r')
  853. X                if (*buf=='\n')
  854. X                    carriage_return--;
  855. X                else
  856. X                    if (fputc('\r',fp)== -1)
  857. X                        return -1;
  858. X                    else
  859. X                        written++;
  860. X
  861. X            Last_Chr= *buf;
  862. X        }
  863. X
  864. X    if (fputc(*buf,fp)== -1)
  865. X        return -1;
  866. X    else
  867. X        written++;
  868. X    }
  869. X
  870. X    return written;
  871. X}
  872. X
  873. static
  874. Receive_File()
  875. X{
  876. X    char *ptr;
  877. X    int N, i;
  878. X    short Request_Resume;
  879. X
  880. X    Result=Overwrite;
  881. X    if (Valid_To_Resume_Download==2)
  882. X        Request_Resume=Resume_Allowed;
  883. X    else
  884. X        Request_Resume=Resume_Not_Allowed;
  885. X
  886. X    if (!(Data_File=QueryCreate(Request_Resume))){
  887. X        Send_Abort();
  888. X        return FAILURE;
  889. X    }
  890. X
  891. X    chown(Name,getuid(),getgid());
  892. X
  893. X    if (Result==Resume){
  894. X        strcpy(tdir,"Attempting receive resume of");
  895. X        showmode();
  896. X
  897. X        init_check();
  898. X
  899. X        do {
  900. X            S_Buffer[0]='N';
  901. X            N=Read(Data_File,&S_Buffer[0],PackeT_Size-1);
  902. X
  903. X            if (N>0){
  904. X                for (i=0;i<N;i++)
  905. X                    do_checksum(S_Buffer[i]);
  906. X                if (Abort_Flag){
  907. X                    Send_Abort();
  908. X                    return FAILURE;
  909. X                }
  910. X
  911. X                already_have+=N;
  912. X            }
  913. X        } while (N>0);
  914. X
  915. X        ptr= &S_Buffer[0];
  916. X
  917. X        *ptr++ ='T';
  918. X        *ptr++ ='r';
  919. X
  920. X        ptr=cnvLtoA(ptr,already_have);
  921. X        *ptr++ =' ';
  922. X        ptr=cnvLtoA(ptr,Checksum);
  923. X
  924. X        if (!Send_Packet(ptr- &S_Buffer[0])||!Flush_Pending()){
  925. X            fclose(Data_File);
  926. X            S0("Can't resume transfer");
  927. X            return FAILURE;
  928. X        }
  929. X
  930. X        fseek(Data_File,0L,2);
  931. X
  932. X        strcpy(tdir,"Resuming receive of");
  933. X        data=already_have-carriage_return;
  934. X        carriage_return= -carriage_return;
  935. X        showmode();
  936. X    } else
  937. X        Send_ACK(),
  938. X        strcpy(tdir,"Receiving"),
  939. X        already_have=0;
  940. X
  941. X    for (;;){
  942. X        if (Abort_Flag){
  943. X            Send_Abort();
  944. X            return FAILURE;
  945. X        }
  946. X
  947. X        Wait_For_ACK(FALSE,TRUE,TRUE);
  948. X
  949. X        if (Packet_Received)
  950. X            switch(R_Buffer[0]){
  951. X            case 'N':
  952. X                if ((N=Write(Data_File,&R_Buffer[1],R_BUffer_Len-1))== -1){
  953. X                    sprintf(Msg,"Disk write error");
  954. X                    S0(Msg);
  955. X                    Send_Failure('I',Msg);
  956. X                    fclose(Data_File);
  957. X                    return FAILURE;
  958. X                }
  959. X
  960. X                stats(N);
  961. X                break;
  962. X
  963. X            case 'T':
  964. X                switch(R_Buffer[1]){
  965. X                case 'I':
  966. X                    fsize=cnvAtoL(&R_Buffer[4]);
  967. X                    showmode();
  968. X                    break;
  969. X
  970. X                case 'C':
  971. X                    fclose(Data_File);
  972. X                    return SUCCESS;
  973. X
  974. X                case 'f':
  975. X                    fclose(Data_File);
  976. X
  977. X                    if (!(Data_File=QueryCreate(Resume_Failed))){
  978. X                        Send_Abort();
  979. X                        return FAILURE;
  980. X                    }
  981. X
  982. X                    chown(Name,getuid(),getgid());
  983. X                    strcpy(tdir,"Receiving");
  984. X                    data=already_have=carriage_return=0;
  985. X                    showmode();
  986. X                    break;
  987. X
  988. X                default:
  989. X                    Send_Unexpected_Packet();
  990. X                    fclose(Data_File);
  991. X                    return FAILURE;
  992. X                }
  993. X                break;
  994. X
  995. X            case 'F':
  996. X                fclose(Data_File);
  997. X                R_Buffer[R_BUffer_Len]=0;
  998. X
  999. X                if (Result==Resume)
  1000. X                    sprintf(Msg,"Can't resume transfer: %s",&R_Buffer[3]);
  1001. X                else
  1002. X                    sprintf(Msg,"B protocol Failure: %s",&R_Buffer[3]);
  1003. X
  1004. X                S0(Msg);
  1005. X                return FAILURE;
  1006. X
  1007. X            default:
  1008. X                Send_Unexpected_Packet();
  1009. X                fclose(Data_File);
  1010. X                return FAILURE;
  1011. X            }
  1012. X        else {
  1013. X            fclose(Data_File);
  1014. X            return FAILURE;
  1015. X        }
  1016. X    }
  1017. X}
  1018. X
  1019. static char *
  1020. Handle_Send_Failure()
  1021. X{
  1022. X    if (!R_BUffer_Len)
  1023. X        return("Remote is not responding");
  1024. X    else {
  1025. X        if (R_Buffer[0]=='F'){
  1026. X            if (R_BUffer_Len>=2){
  1027. X                    R_Buffer[min(81,R_BUffer_Len)]='\0';
  1028. X                    return(&R_Buffer[1]);
  1029. X                } else
  1030. X                    return("No reason given by remote");
  1031. X        } else {
  1032. X            Send_Failure('E',"Unexpected packet type");
  1033. X            return("Unexpected packet type");
  1034. X        }
  1035. X    }
  1036. X}
  1037. X
  1038. static
  1039. Send_File()
  1040. X{
  1041. X    int N;
  1042. X    struct stat statbuf;
  1043. X
  1044. X    if (!(Data_File=fopen(Name,"r"))){
  1045. X        sprintf(Msg,"Can't access '%s'",Name);
  1046. X        S0(Msg);
  1047. X        Send_Failure('M',Msg);
  1048. X        return FAILURE;
  1049. X    }
  1050. X
  1051. X    fstat(fileno(Data_File),&statbuf);
  1052. X    fsize=statbuf.st_size;
  1053. X
  1054. X    strcpy(tdir,"Transmitting");
  1055. X    showmode();
  1056. X
  1057. X    do {
  1058. X        S_Buffer[0]='N';
  1059. X        N=Read(Data_File,&S_Buffer[1],PackeT_Size-1);
  1060. X
  1061. X        if (N>0){
  1062. X            if (!Send_Packet(N+1)){
  1063. X                fclose(Data_File);
  1064. X                S0(Handle_Send_Failure());
  1065. X                return FAILURE;
  1066. X            }
  1067. X
  1068. X            if (Abort_Flag){
  1069. X                Send_Abort();
  1070. X                return FAILURE;
  1071. X            }
  1072. X
  1073. X            stats(N);
  1074. X        }
  1075. X    } while (N>0);
  1076. X
  1077. X    if (!N){
  1078. X        fclose(Data_File);
  1079. X        S_Buffer[0]='T';
  1080. X        S_Buffer[1]='C';
  1081. X
  1082. X        if (!Send_Packet(2)){
  1083. X            S0(Handle_Send_Failure());
  1084. X            return FAILURE;
  1085. X        }
  1086. X
  1087. X        return Flush_Pending();
  1088. X    } else {
  1089. X        sprintf(Msg,"Disk read error");
  1090. X        S0(Msg);
  1091. X        Send_Failure('I',Msg);
  1092. X        return FAILURE;
  1093. X    }
  1094. X}
  1095. X
  1096. X#define Plus_PackeT_Size    18
  1097. X#define LowRange        7
  1098. X#define HiRange            11
  1099. X
  1100. X#define My_Send_Window_Size    1
  1101. X#define My_Recv_Window_Size    1
  1102. X#define My_Buffer_Size        8
  1103. X#define My_Check_Method        Check_CRC
  1104. X#define My_Download_Resume    2
  1105. X#define My_Upload_Resume    0
  1106. X#define My_File_Information    1
  1107. X
  1108. static char Quote_Level_Select_Low[]={
  1109. X    1, 3, 3, 0, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  1110. X    0, 0, 3, 0, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
  1111. X};
  1112. X
  1113. X
  1114. static char QuotE_Level_select_Hi[]={
  1115. X    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  1116. X    3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
  1117. X};
  1118. X
  1119. static char QUote_Level_Mapping[]={
  1120. X    Quote_Not_NULL,
  1121. X    Quote_Default,
  1122. X    Quote_Extended,
  1123. X    Quote_Full
  1124. X};
  1125. X
  1126. static
  1127. Plus_Respond()
  1128. X{
  1129. X    int Status, temp_window_size, temp_method, temp_size, MaskByte, Bit, i;
  1130. X    char Estimated_Quote_Level=0;
  1131. X
  1132. X    S_Buffer[0]='+';
  1133. X    S_Buffer[1]=My_Send_Window_Size;
  1134. X    S_Buffer[2]=My_Recv_Window_Size;
  1135. X
  1136. X    S_Buffer[3]=PackeT_Size/128;
  1137. X
  1138. X    S_Buffer[4]=My_Check_Method;
  1139. X
  1140. X    S_Buffer[5]=Quote_Default;
  1141. X    S_Buffer[6]=FALSE;
  1142. X
  1143. X    S_Buffer[15]=My_Download_Resume;
  1144. X    S_Buffer[16]=My_Upload_Resume;
  1145. X    S_Buffer[17]=My_File_Information;
  1146. X
  1147. X    for (i=0;i<8;i++)
  1148. X        S_Buffer[i+LowRange]=0;
  1149. X
  1150. X    for (MaskByte=0;MaskByte<4;MaskByte++)
  1151. X        for (Bit=0;Bit<8;Bit++){
  1152. X            if (Mask[MaskByte*8+Bit]&MaskLowRange)
  1153. X                S_Buffer[MaskByte+LowRange]|=0x80>>Bit;
  1154. X
  1155. X            if (Mask[MaskByte*8+Bit]&MaskHiRange)
  1156. X                S_Buffer[MaskByte+HiRange]|=0x80>>Bit;
  1157. X        }
  1158. X
  1159. X    for (i=R_BUffer_Len;i<Plus_PackeT_Size;i++)
  1160. X        R_Buffer[i]=0;
  1161. X
  1162. X    if (R_Buffer[3]<S_Buffer[3])
  1163. X        temp_size=(R_Buffer[3]*128)+1;
  1164. X    else
  1165. X        temp_size=(S_Buffer[3]*128)+1;
  1166. X
  1167. X
  1168. X    temp_window_size=min(R_Buffer[2],My_Send_Window_Size);
  1169. X    temp_method=min(R_Buffer[4],My_Check_Method);
  1170. X    Valid_To_Resume_Download=min(R_Buffer[15],My_Download_Resume);
  1171. X    ValiD_To_Resume_Upload=min(R_Buffer[16],My_Upload_Resume);
  1172. X    Send_FIle_Information=min(R_Buffer[17],My_File_Information);
  1173. X
  1174. X    if (R_BUffer_Len>=Plus_PackeT_Size)
  1175. X        for (MaskByte=0;MaskByte<4;MaskByte++)
  1176. X            for (Bit=0;Bit<8;Bit++){
  1177. X                if (R_Buffer[LowRange+MaskByte]&(0x80>>Bit))
  1178. X                    Mask[MaskByte*8+Bit]|=MaskLowRange;
  1179. X
  1180. X                if (R_Buffer[HiRange+MaskByte]&(0x80>>Bit))
  1181. X                    Mask[MaskByte*8+Bit]|=MaskHiRange;
  1182. X            }
  1183. X    else {
  1184. X        for (i=0;i<32&&Estimated_Quote_Level<3;i++){
  1185. X            if (Mask[i]&MaskLowRange)
  1186. X                Estimated_Quote_Level=
  1187. X                    max(Quote_Level_Select_Low[i],Estimated_Quote_Level);
  1188. X
  1189. X            if (Mask[i]&MaskHiRange)
  1190. X                Estimated_Quote_Level=
  1191. X                    max(QuotE_Level_select_Hi[i],Estimated_Quote_Level);
  1192. X        }
  1193. X    }
  1194. X
  1195. X    Quoting=Quote_Full;
  1196. X    S_Buffer[5]=QUote_Level_Mapping[Estimated_Quote_Level];
  1197. X
  1198. X    if (Status=Send_Packet(Plus_PackeT_Size))
  1199. X        if (Status=Flush_Pending()){
  1200. X            Actual_Check=temp_method;
  1201. X            PackeT_Size=temp_size;
  1202. X            Window_Size=temp_window_size;
  1203. X        }
  1204. X    Quoting=Quote_Mask;
  1205. X
  1206. X    return Status;
  1207. X}
  1208. X
  1209. static
  1210. Do_Transfer()
  1211. X{
  1212. X    int I, N;
  1213. X    short Have_DLE_B=TRUE;
  1214. X
  1215. X    for (;;){
  1216. X        Wait_For_ACK(Have_DLE_B,FALSE,TRUE);
  1217. X        if (Packet_Received){
  1218. X            if (R_Buffer[0]=='T'){
  1219. X                if (R_Buffer[1]!='D'&&R_Buffer[1]!='U'){
  1220. X                    S0("Invalid transfer direction");
  1221. X                    Send_Failure('N',"Not implemented");
  1222. X                    return FAILURE;
  1223. X                }
  1224. X                if (R_Buffer[2]!='A'&&R_Buffer[2]!='B'){
  1225. X                    S0("Invalid transfer type");
  1226. X                    Send_Failure('N',"Not implemented");
  1227. X                    return FAILURE;
  1228. X                }
  1229. X                N=min(R_BUffer_Len-3,SM_BUFF-1);
  1230. X                for (I=0;I<N;I++)
  1231. X                    Name[I]=R_Buffer[I+3];
  1232. X                Name[I]='\0';
  1233. X                textmode=(R_Buffer[2]=='A');
  1234. X
  1235. X                if (R_Buffer[1]=='U'){
  1236. X                    Send_ACK();
  1237. X                    return Send_File();
  1238. X                } else
  1239. X                    return Receive_File();
  1240. X
  1241. X            } else if (R_Buffer[0]=='+'){
  1242. X                if (Plus_Respond())
  1243. X                    Have_DLE_B=FALSE;
  1244. X                else {
  1245. X                    S0("Could not negotiate B-Plus parameters");
  1246. X                    return FAILURE;
  1247. X                }
  1248. X            } else {
  1249. X                Send_Unexpected_Packet();
  1250. X                return FAILURE;
  1251. X            }
  1252. X        } else {
  1253. X            S0("Remote is not responding");
  1254. X            return FAILURE;
  1255. X        }
  1256. X    }
  1257. X}
  1258. X
  1259. static
  1260. void cisbsigint(junk)
  1261. int junk;
  1262. X{
  1263. X    signal(SIGINT,cisbsigint);
  1264. X    Abort_Flag=TRUE;
  1265. X}
  1266. X
  1267. void
  1268. B_Transfer()
  1269. X{
  1270. X    short Status=FALSE;
  1271. X    void (*oldvec)();
  1272. X
  1273. X    oldvec = signal(SIGINT,cisbsigint);
  1274. X    cur_off();
  1275. X    Init();
  1276. X    purge();
  1277. X    Send_Byte(DLE);
  1278. X    Send_Byte('+');
  1279. X    Send_Byte('+');
  1280. X    Send_ACK();
  1281. X
  1282. X    Read_Byte();
  1283. X    switch(Ch){
  1284. X    case DLE:
  1285. X        Read_Byte();
  1286. X        if (Ch=='B')
  1287. X            Status=Do_Transfer();
  1288. X        break;
  1289. X
  1290. X    default:
  1291. X        fputc(Ch,tfp);
  1292. X        break;
  1293. X    }
  1294. X
  1295. X    sprintf(Msg,"File Transfer %s",Status?"Succeeded":"Failed");
  1296. X    S0(Msg);
  1297. X    beep();
  1298. X
  1299. X    if (Abort_Flag){
  1300. X        while (Read_Byte() && Ch==ENQ){
  1301. X            Seq_Num=0;
  1302. X            Send_Byte(DLE);
  1303. X            Send_Byte('+');
  1304. X            Send_Byte('+');
  1305. X            Send_ACK();
  1306. X        }
  1307. X    }
  1308. X
  1309. X    cur_on();
  1310. X    signal(SIGINT,oldvec);
  1311. X}
  1312. END_OF_FILE
  1313. if test 22715 -ne `wc -c <'xcb+.c'`; then
  1314.     echo shar: \"'xcb+.c'\" unpacked with wrong size!
  1315. fi
  1316. # end of 'xcb+.c'
  1317. fi
  1318. if test -f 'xcmain.c' -a "${1}" != "-c" ; then 
  1319.   echo shar: Will not clobber existing file \"'xcmain.c'\"
  1320. else
  1321. echo shar: Extracting \"'xcmain.c'\" \(17053 characters\)
  1322. sed "s/^X//" >'xcmain.c' <<'END_OF_FILE'
  1323. X/*    xcmain.c -- main module for XC
  1324. X    This file uses 4-character tabstops
  1325. X*/
  1326. X
  1327. X#include <stdio.h>
  1328. X#include <string.h>
  1329. X#include <sys/types.h>
  1330. X#include <signal.h>
  1331. X#include <ctype.h>
  1332. X#include <termio.h>
  1333. X#include <sys/ioctl.h>
  1334. X#include <setjmp.h>
  1335. X#include "xc.h"
  1336. X
  1337. X#define Resume_Not_Allowed    1
  1338. X
  1339. short
  1340. X    autoflag =    FALSE,    /* Automatic capturing */
  1341. X    cismode =    FALSE,    /* Automatic response to CIS "ENQ" */
  1342. X    cr_add =    TRUE,    /* Add cr to nl in B+ uploads */
  1343. X    hdplxflag =    FALSE,    /* Half-duplex mode */
  1344. X     menuflag =    TRUE,    /* Show mini-menu */
  1345. X    nl2cr =        TRUE,    /* Map nl to cr when transmitting ASCII */
  1346. X    reterm =    FALSE,    /* Jumping into terminal mode */
  1347. X    statflag =    FALSE,    /* Flag for status display */
  1348. X    eofflag =    FALSE;    /* Flag to quit a script */
  1349. int s_cis(), s_set(), s_exit(), s_shell();
  1350. char Msg[SM_BUFF];
  1351. unchar BS, LK;
  1352. XFILE *tfp;
  1353. struct termio newmode, oldmode, sigmode;
  1354. static char    *statfmt = "\r\t\t%-8s %25s %s\r\n",
  1355. X            version[]="@(#)XC 4.1 JPRadley 10 April 1993",
  1356. X            oldshell[SM_BUFF],
  1357. X            *babble[] = {
  1358. X                "\r\nUsage: xc [-l device] [-s file | -t]",
  1359. X                "\t-l device\tUse 'device' as the modem port",
  1360. X                "\t-s script\tExecute 'script' immediately",
  1361. X                "\t-t\t\tEnter terminal mode immediately",
  1362. X                NIL(char)
  1363. X            };
  1364. static s_script(), s_xmodem(), s_term(), s_help(), s_dial(), puttake(),
  1365. X    SET_proto(), SET_cr(), SET_cis(), SET_nl(), SET_xon(), SET_xcape(),
  1366. X    SET_menu(), SET_hdplx(), SET_bps(), SET_autocapt(), SET_cfile(),
  1367. X    SET_pfile();
  1368. extern short scriptflag;
  1369. extern void B_Transfer(), dbglog(), mattach(), terminal(), xreceive(), xsend(),
  1370. X    get_ttype(), unlock_tty();
  1371. jmp_buf erret;            /* non-local error return */
  1372. X
  1373. struct kw {                /* Used by command parsing routines */
  1374. X    char *keyword;
  1375. X    int (*rtn)();
  1376. X};
  1377. X
  1378. static struct kw cmds[] = {
  1379. X    {"c",        s_cis},
  1380. X    {"cis",        s_cis},
  1381. X    {"s",        s_script},
  1382. X    {"script",    s_script},
  1383. X    {"h",        hangup},
  1384. X    {"hangup",    hangup},
  1385. X    {"bindings",show_bindings},
  1386. X    {"rb",        s_xmodem},
  1387. X    {"rt",        s_xmodem},
  1388. X    {"sb",        s_xmodem},
  1389. X    {"st",        s_xmodem},
  1390. X    {"set",        s_set},
  1391. X    {"t",        s_term},
  1392. X    {"term",    s_term},
  1393. X    {"d",        s_dial},
  1394. X    {"dial",    s_dial},
  1395. X    {"q",        s_exit},
  1396. X    {"quit",    s_exit},
  1397. X    {"exit",    s_exit},
  1398. X    {"x",        s_exit},
  1399. X    {"!",        s_shell},
  1400. X    {"!!",        s_shell},
  1401. X    {"$",        s_shell},
  1402. X    {"%p",        puttake},
  1403. X    {"%t",        puttake},
  1404. X    {"help",    s_help},
  1405. X    {"?",        s_help},
  1406. X    {NIL(char),    0}
  1407. X};
  1408. X
  1409. static struct kw setlist[] = {
  1410. X    {"auto",    SET_autocapt},
  1411. X    {"baud",    SET_bps},
  1412. X    {"bps",        SET_bps},
  1413. X    {"cfile",    SET_cfile},
  1414. X    {"cis",        SET_cis},
  1415. X    {"cr",        SET_cr},
  1416. X    {"hdplx",    SET_hdplx},
  1417. X    {"menu",    SET_menu},
  1418. X    {"nl",        SET_nl},
  1419. X    {"pfile",    SET_pfile},
  1420. X    {"proto",    SET_proto},
  1421. X    {"escape",    SET_xcape},
  1422. X    {"xcape",    SET_xcape},
  1423. X    {"xon",        SET_xon},
  1424. X    {"xoff",    SET_xon},
  1425. X    {NIL(char),    0}
  1426. X};
  1427. X
  1428. X/* Print the status of the program */
  1429. static void
  1430. status()
  1431. X{
  1432. X    struct kw *ptr;
  1433. X    char p[30];
  1434. X    int (*fct)() = 0;
  1435. X
  1436. X    statflag = TRUE;
  1437. X
  1438. X    cls();
  1439. X    cur_off();
  1440. X    sprintf(p,"Modem Port: %s",mport(NIL(char)));
  1441. X    drawline(0, 0, CO);
  1442. X    ttgoto(1, 9);
  1443. X    sprintf(Msg,"%-29s%29s",&version[4], p);
  1444. X    S;
  1445. X    drawline(2, 0, CO);
  1446. X    ttgoto(3, 0);
  1447. X    fprintf(tfp, statfmt, "Keyword", "Description", "Status");
  1448. X    fprintf(tfp, statfmt, "--------", "-------------------------", "-----------");
  1449. X
  1450. X    for (ptr = setlist; ptr->keyword; ptr++)
  1451. X        if (ptr->rtn != fct){
  1452. X            fct = ptr->rtn;
  1453. X            (*fct)();
  1454. X        }
  1455. X
  1456. X    ttgoto(18, 25);
  1457. X    S1("Type \"help\" or ? for help");
  1458. X    statflag = FALSE;
  1459. X    cur_on();
  1460. X}
  1461. X
  1462. X/* Catch a signal and jump to main. Reset signal and do a longjmp */
  1463. static void
  1464. catch(junk)
  1465. int junk;
  1466. X{
  1467. X    if (! isatty(2))
  1468. X        hangup(),
  1469. X        s_exit();
  1470. X
  1471. X    S2("XC: Interrupt");
  1472. X
  1473. X    signal(SIGINT,catch);
  1474. X    signal(SIGQUIT,catch);
  1475. X    longjmp(erret,1);
  1476. X}
  1477. X
  1478. static void
  1479. usage()
  1480. X{
  1481. X    char **ptr;
  1482. X
  1483. X    for (ptr = babble; *ptr; ptr++)
  1484. X        fprintf(tfp, "%s\r\n", *ptr);
  1485. X}
  1486. X
  1487. main(argc, argv)
  1488. int argc;
  1489. char **argv;
  1490. X{
  1491. X    char *script = NIL(char);
  1492. X    extern char *optarg;
  1493. X    int c;
  1494. X    extern int optind;
  1495. X
  1496. X    struct kw *ptr;
  1497. X    tfp = stderr;
  1498. X    if (isatty(2))
  1499. X        get_ttype();
  1500. X
  1501. X    ioctl(0, TCGETA, &oldmode);    /* get current tty mode    */
  1502. X
  1503. X    /* trap for SIGHUP and SIGTERM, make sure LCKfile gets killed */
  1504. X    signal(SIGHUP,(void *)s_exit);
  1505. X    signal(SIGTERM,(void *)s_exit);
  1506. X
  1507. X    newmode = oldmode;
  1508. X
  1509. X    newmode.c_iflag &= ~(IXON | IXOFF | IXANY);
  1510. X    newmode.c_lflag &= ~(ICANON | ISIG | ECHO);
  1511. X    newmode.c_oflag = 0;
  1512. X    newmode.c_cc[VMIN] = 1;
  1513. X    newmode.c_cc[VTIME] = 1;
  1514. X    BS = newmode.c_cc[VERASE];
  1515. X    LK = newmode.c_cc[VKILL];
  1516. X
  1517. X    sigmode = newmode;
  1518. X    sigmode.c_lflag |= ISIG;
  1519. X
  1520. X    oldshell[0] = '\0';    /* set last command to blank */
  1521. X    if (setjmp(erret))    /* set error handler to exit */
  1522. X        exit(0);        /*  while parsing command line */
  1523. X    signal(SIGINT,catch);    /* catch break & quit signals/keys */
  1524. X    signal(SIGQUIT,catch);
  1525. X
  1526. X    default_bindings();
  1527. X
  1528. X    while ((c = getopt(argc, argv, "s:l:t")) != -1)
  1529. X        switch (c){
  1530. X        case 'l':    /* set modem port name */
  1531. X            mport(optarg);
  1532. X            break;
  1533. X        case 's':    /* Execute SCRIPT file */
  1534. X            script = optarg;
  1535. X            break;
  1536. X        case 't':    /* jump into terminal mode */
  1537. X            reterm = TRUE;
  1538. X            break;
  1539. X        default:    /* Bad command .. print help */
  1540. X            usage();
  1541. X            exit(1);
  1542. X        }
  1543. X
  1544. X    setuid(geteuid());
  1545. X    setgid(getegid());
  1546. X
  1547. X    mopen();    /* opens and configures modem port, or exits */
  1548. X
  1549. X    setuid(getuid());
  1550. X    setgid(getgid());
  1551. X
  1552. X    do_script(STARTUP);
  1553. X
  1554. X#if DEBUG
  1555. X    dbglog();
  1556. X#endif
  1557. X
  1558. X    if (!script)
  1559. X        status();
  1560. X
  1561. X    for (;;){
  1562. X        setjmp(erret);
  1563. X        signal(SIGQUIT,(void *)s_exit);
  1564. X        mode(SIGMODE);
  1565. X
  1566. X        if (script)
  1567. X            do_script(script),
  1568. X            script = NIL(char),
  1569. X            reterm = TRUE;
  1570. X
  1571. X        if (reterm && isatty(2)){
  1572. X            s_term();
  1573. X            continue;
  1574. X        }
  1575. X
  1576. X        fputc('\r',tfp),
  1577. X        fputc('\n',tfp);
  1578. X         if (menuflag)
  1579. X            fputc('\t',tfp),
  1580. X             S1("[d]ial directory  [t]erminal mode  [q]uit  [s]cript  [?]help");
  1581. X        show(-1,"<XC>");
  1582. X        fputc(' ',tfp);
  1583. X
  1584. X        lptr = line;
  1585. X        getline();
  1586. X        fputc('\r',tfp),
  1587. X        fputc('\n',tfp);
  1588. X
  1589. X        getword();
  1590. X        lc_word(word);
  1591. X        if (word[0] == '\0')        /* If blank line... reprompt */
  1592. X            continue;
  1593. X
  1594. X        for (ptr = cmds; ptr->keyword; ptr++)
  1595. X            if (!strcmp(word, ptr->keyword))
  1596. X                break;
  1597. X
  1598. X        if (ptr->keyword)
  1599. X            (*ptr->rtn)();
  1600. X        else
  1601. X            sprintf(Msg,"Unrecognized command: %s",word),
  1602. X            S;
  1603. X    }
  1604. X}
  1605. X
  1606. static
  1607. s_script()
  1608. X{
  1609. X    getword();
  1610. X
  1611. X    if (word[0] == '\0'){
  1612. X        S1("Script file not specified");
  1613. X        return;
  1614. X    }
  1615. X
  1616. X    sprintf(ddsname,"%s",word);
  1617. X    do_script(ddsname);
  1618. X    reterm = TRUE;
  1619. X}
  1620. X
  1621. static
  1622. s_xmodem()
  1623. X{
  1624. X    char d = word[0];
  1625. X    char c = word[1];
  1626. X    char oldproto[4];
  1627. X
  1628. X    strcpy(oldproto, protocol);
  1629. X
  1630. X    xc_setflow(FALSE);
  1631. X    xc_setproto("8N1");
  1632. X
  1633. X    getword();
  1634. X    if (word[0] == '\0')
  1635. X        S1("Transfer file not specified");
  1636. X    else if (d == 's')
  1637. X        xsend(c);
  1638. X    else
  1639. X        xreceive(c);
  1640. X
  1641. X    reterm = TRUE;
  1642. X    xc_setflow(flowflag);
  1643. X    xc_setproto(oldproto);
  1644. X}
  1645. X
  1646. static
  1647. s_term()
  1648. X{
  1649. X    terminal(FALSE);
  1650. X    if (cismode != 2)
  1651. X        return;
  1652. X    cismode = 1;
  1653. X    s_cis();
  1654. X}
  1655. X
  1656. static
  1657. s_dial()
  1658. X{
  1659. X    terminal(TRUE);
  1660. X    if (cismode != 2)
  1661. X        return;
  1662. X    cismode = 1;
  1663. X    s_cis();
  1664. X}
  1665. X
  1666. s_cis()
  1667. X{
  1668. X    char oldproto[4];
  1669. X
  1670. X    strcpy(oldproto, protocol);
  1671. X
  1672. X    xc_setflow(FALSE);
  1673. X    xc_setproto("8N1");
  1674. X    mode(SIGMODE);
  1675. X
  1676. X    B_Transfer();
  1677. X
  1678. X    reterm = TRUE;
  1679. X    xc_setflow(flowflag);
  1680. X    xc_setproto(oldproto);
  1681. X}
  1682. X
  1683. s_shell()
  1684. X{
  1685. X    int stat_loc = 0;
  1686. X    char c = word[0];
  1687. X    static char *shell = NIL(char);
  1688. X    void (*oldvec)();
  1689. X
  1690. X#if NOSHELL
  1691. X    return(0);
  1692. X#endif
  1693. X    if (word[0] == word[1])
  1694. X        strcpy(wptr = word, oldshell);
  1695. X    else {
  1696. X        getword();
  1697. X        if (*wptr)
  1698. X            strcpy(oldshell, wptr);
  1699. X    }
  1700. X
  1701. X    if (!shell){
  1702. X        shell = getenv("SHELL");
  1703. X        if (!shell)
  1704. X            shell = "/bin/sh";
  1705. X    }
  1706. X
  1707. X    fputc('\r',tfp),
  1708. X    fputc('\n',tfp);
  1709. X    mode(OLDMODE);
  1710. X
  1711. X    if (!forkem()){
  1712. X        if (c == '$')    /* Attach modem to stdin, stdout */
  1713. X            mattach();
  1714. X        signal(SIGCLD,SIG_DFL);
  1715. X        signal(SIGINT,SIG_DFL);
  1716. X        signal(SIGQUIT,SIG_DFL);
  1717. X        if (word[0] == '\0')
  1718. X            execl(shell, shell, "-i", NIL(char));
  1719. X        else
  1720. X            execl(shell, shell, "-c", wptr, NIL(char));
  1721. X        S1("Exec failed!");
  1722. X        exit(2);
  1723. X    }
  1724. X
  1725. X    oldvec = signal(SIGINT,SIG_IGN);
  1726. X    wait(&stat_loc);
  1727. X    signal(SIGINT,oldvec);
  1728. X
  1729. X    strcpy(oldshell, wptr);
  1730. X    return(!!stat_loc);
  1731. X}
  1732. X
  1733. static char    *cmdlist[] = {
  1734. X    "\tXC Command Summary",
  1735. X    "",
  1736. X    "\tc",
  1737. X    "\tcis\t\tInitiate CIS B+ File Transfer (Upload and Download)",
  1738. X    "",
  1739. X    "\td",
  1740. X    "\tdial\t\tDialing directory",
  1741. X    "",
  1742. X    "\tx",
  1743. X    "\tq",
  1744. X    "\texit",
  1745. X    "\tquit\t\tExit XC",
  1746. X    "",
  1747. X    "\th",
  1748. X    "\thangup\t\tHang up the modem",
  1749. X    "",
  1750. X    "\trb file\t\tXMODEM receive file 'file' (binary mode)",
  1751. X    "\trt file\t\tXMODEM receive file 'file' (Ascii mode)",
  1752. X    "",
  1753. X    "\tsb file...\tXMODEM send file 'file' (binary mode)",
  1754. X    "\tst file...\tXMODEM send file 'file' (Ascii mode)",
  1755. X    "",
  1756. X    "\tset\t\tDisplay XC parameters",
  1757. X    "\tset kw\t\tDisplay XC parameter for 'kw'",
  1758. X    "\tset kw val\tSet XC keyword 'kw' to 'val'",
  1759. X    "",
  1760. X    "\ts file",
  1761. X    "\tscript file\tExecute XC script 'file'",
  1762. X    "",
  1763. X    "\tt",
  1764. X    "\tterm\t\tEnter terminal mode",
  1765. X    "",
  1766. X#if !NOSHELL
  1767. X    "\t!\t\tExecute a local interactive shell",
  1768. X    "\t! cmd\t\tExecute shell command string on the local system",
  1769. X    "\t!!\t\tRe-execute the last shell command string",
  1770. X    "",
  1771. X    "\t$ cmd\t\tShell command with stdin and stdout redirected to modem",
  1772. X    "",
  1773. X#endif
  1774. X    "\t%p loc [rem]\tPut local file to a UNIX system",
  1775. X    "",
  1776. X    "\t%t rem [loc]\tTake remote file from a UNIX system",
  1777. X    "",
  1778. X    "\t?",
  1779. X    "\thelp\t\tPrint (this) help text",
  1780. X    " ",
  1781. X    "\tSET Keywords:",
  1782. X    "",
  1783. X    "\tset\t\t\tDisplay current XC status",
  1784. X    "",
  1785. X    "\tset auto on|off\t\tSet|Unset automatic capturing",
  1786. X    "",
  1787. X    "\tset bps value",
  1788. X    "\tset baud value\t\tSet Bits/Second to 'value'",
  1789. X    "",
  1790. X    "\tset cfile name\t\tChange name of capture file",
  1791. X    "",
  1792. X    "\tset cis on\t\tSet CIS <ENQ> mode (Auto up/download)",
  1793. X    "\tset cis off\t\tDo not respond to <ENQ>",
  1794. X    "",
  1795. X    "\tset cr on|off\t\tSet|Unset Carriage Return Injection mode",
  1796. X    "",
  1797. X    "\tset xcape char",
  1798. X    "\tset escape char\t\tSet the Terminal mode escape character",
  1799. X    "",
  1800. X    "\tset hdplx on\t\tSet half-duplex mode",
  1801. X    "\tset hdplx off\t\tUnset half-duplex mode (use full-duplex)",
  1802. X    "",
  1803. X     "\tset menu on|off\t\tDo|Don't show mini-menu before XC prompt",
  1804. X    "",
  1805. X    "\tset nl on|off\t\tSet|Unset newline translation",
  1806. X    "",
  1807. X    "\tset pfile name\t\tChange name of phonelist file",
  1808. X    "",
  1809. X    "\tset proto 7E2\t\tSet 7-bit character size, even parity",
  1810. X    "\tset proto 7O2\t\tSet 7-bit character size, odd parity",
  1811. X    "\tset proto 8N1\t\tSet 8-bit character size, no parity",
  1812. X    "",
  1813. X    "\tset xon on|off",
  1814. X    "\tset xoff on|off\t\tSet|Unset XON/XOFF flow control",
  1815. X    "",
  1816. X    " ",
  1817. X    NIL(char) };
  1818. X
  1819. static
  1820. s_help()
  1821. X{
  1822. X    char **ptr = cmdlist;
  1823. X    int curline = 0;
  1824. X
  1825. X    mode(OLDMODE);
  1826. X    cls();
  1827. X    cur_off();
  1828. X    for ( ; *ptr; ptr++) {
  1829. X        if (**ptr != ' ') {
  1830. X            if (curline >= LI-2){
  1831. X                S0("PRESS ENTER");
  1832. X                getline();
  1833. X                cls();
  1834. X                curline = 0;
  1835. X            }
  1836. X            fprintf(tfp, "%s\r\n", *ptr);
  1837. X            curline++;
  1838. X        } else {
  1839. X            S0("PRESS ENTER");
  1840. X            getline();
  1841. X            cls();
  1842. X            curline = 0;
  1843. X        }
  1844. X    }
  1845. X    show_bindings();
  1846. X    S0("PRESS ENTER");
  1847. X    getline();
  1848. X    cls();
  1849. X    status();
  1850. X}
  1851. X
  1852. s_set()
  1853. X{
  1854. X    struct kw *ptr;
  1855. X
  1856. X    getword();
  1857. X
  1858. X    if (word[0] == '\0' && !scriptflag){
  1859. X        status();
  1860. X        return;
  1861. X    } else if (word[0] == '\0'){
  1862. X        S1("SET keyword requires an argument");
  1863. X        eofflag++;
  1864. X        return;
  1865. X    }
  1866. X
  1867. X    lc_word(word);
  1868. X
  1869. X    for (ptr = setlist; ptr->keyword; ptr++)
  1870. X        if (!strcmp(ptr->keyword, word)){
  1871. X            (*ptr->rtn)();
  1872. X            return;
  1873. X        }
  1874. X
  1875. X    sprintf(Msg,"Invalid SET keyword: %s", word);
  1876. X    S;
  1877. X    eofflag++;
  1878. X}
  1879. X
  1880. void
  1881. set_onoff(flag)
  1882. short *flag;
  1883. X{
  1884. X    char *ptr = strdup(word);
  1885. X
  1886. X    uc_word(ptr);
  1887. X    getword();
  1888. X    lc_word(word);
  1889. X
  1890. X    if (!strcmp(word, "on"))
  1891. X        *flag = TRUE;
  1892. X    else if (!strcmp(word, "off"))
  1893. X        *flag = FALSE;
  1894. X    else
  1895. X        sprintf(Msg,"Set '%s' value must be 'on' or 'off'",ptr),
  1896. X        S,
  1897. X        eofflag++;
  1898. X
  1899. X    free(ptr);
  1900. X}
  1901. X
  1902. static
  1903. SET_proto()
  1904. X{
  1905. X    if (statflag){
  1906. X        fprintf(tfp, statfmt, "proto", "Port set to", protocol);
  1907. X        return;
  1908. X    }
  1909. X
  1910. X    getword();
  1911. X    uc_word(word);
  1912. X    if (word[0] == '\0')
  1913. X        S1("Set proto must be 7E2, 7O2, or 8N1");
  1914. X    else if (!xc_setproto(word))
  1915. X        sprintf(Msg,"Unsupported protocol %s",word),
  1916. X        S;
  1917. X    eofflag++;
  1918. X
  1919. X    if (!scriptflag)
  1920. X        sprintf(Msg,"Port set to %s", protocol),
  1921. X        S;
  1922. X}
  1923. X
  1924. static
  1925. SET_cr()
  1926. X{
  1927. X    if (statflag){
  1928. X        fprintf(tfp, statfmt, "cr", "Carriage Return Injection",
  1929. X            cr_add ? "ON" : "OFF");
  1930. X        return;
  1931. X    }
  1932. X
  1933. X    set_onoff(&cr_add);
  1934. X
  1935. X    if (!scriptflag)
  1936. X        sprintf(Msg,"Carriage Returns %s injected in B+ ASCII uploads",
  1937. X            cr_add ? "ARE" : "are NOT"),
  1938. X        S;
  1939. X}
  1940. X
  1941. static
  1942. SET_xcape()
  1943. X{
  1944. X    if (statflag) {
  1945. X        fprintf(tfp, statfmt, "xcape", "Terminal Escape Character",
  1946. X                 unctrl(my_escape));
  1947. X        return;
  1948. X    }
  1949. X
  1950. X    getword();
  1951. X    if (word[0] == '\0') {
  1952. X        show(1,"Set ESCAPE must specify escape character");
  1953. X        eofflag++;
  1954. X        return;
  1955. X    }
  1956. X
  1957. X    my_escape = word[0];
  1958. X
  1959. X    if (!scriptflag)
  1960. X        sprintf(Msg,"Terminal mode escape character set to '%s'",
  1961. X                unctrl(my_escape)),
  1962. X        S;
  1963. X}
  1964. X
  1965. static
  1966. SET_nl()
  1967. X{
  1968. X    if (statflag){
  1969. X        fprintf(tfp, statfmt, "nl", "Newline Translation",
  1970. X            nl2cr ? "ON" : "OFF");
  1971. X        return;
  1972. X    }
  1973. X
  1974. X    set_onoff(&nl2cr);
  1975. X
  1976. X    if (!scriptflag)
  1977. X        sprintf(Msg,"Newlines %s changed to Carriage Returns",
  1978. X            nl2cr ? "ARE" : "are NOT"),
  1979. X        S;
  1980. X}
  1981. X
  1982. static
  1983. SET_cis()
  1984. X{
  1985. X    if (statflag){
  1986. X        fprintf(tfp, statfmt, "cis", "CIS <ENQ> Auto Download",
  1987. X            cismode ? "ON" : "OFF");
  1988. X        return;
  1989. X    }
  1990. X
  1991. X    set_onoff(&cismode);
  1992. X
  1993. X    if (!scriptflag)
  1994. X        sprintf(Msg,"CIS <ENQ> Auto Download is %s", cismode ? "ON" : "OFF"),
  1995. X        S;
  1996. X}
  1997. X
  1998. static
  1999. SET_xon()
  2000. X{
  2001. X    if (statflag){
  2002. X        fprintf(tfp, statfmt, "xoff", "Terminal Mode XON/XOFF",
  2003. X            flowflag ? "ON" : "OFF");
  2004. X        return;
  2005. X    }
  2006. X
  2007. X    set_onoff(&flowflag);
  2008. X    xc_setflow(flowflag);
  2009. X
  2010. X    if (!scriptflag)
  2011. X        sprintf(Msg,"XON/XOFF Flow control is %s", flowflag ? "ON" : "OFF"),
  2012. X        S;
  2013. X}
  2014. X
  2015. static
  2016. SET_bps()
  2017. X{
  2018. X    if (statflag){
  2019. X        char br[6];
  2020. X        sprintf(br, "%d", mrate(NIL(char)));
  2021. X        fprintf(tfp, statfmt, "bps", "Bits per Second", br);
  2022. X        return;
  2023. X    }
  2024. X
  2025. X    getword();
  2026. X    if (word[0] == '\0')
  2027. X        S1("Set BPS (or BAUD) must have a rate");
  2028. X    else if (!mrate(word))
  2029. X        sprintf(Msg,"Unsupported bps rate %s",word),
  2030. X        S;
  2031. X    eofflag++;
  2032. X    if (!scriptflag)
  2033. X        sprintf(Msg,"Bits/Second set to %d",mrate(NIL(char))),
  2034. X        S;
  2035. X}
  2036. X
  2037. static
  2038. SET_hdplx()
  2039. X{
  2040. X    if (statflag){
  2041. X        fprintf(tfp, statfmt, "hdplx", "Half-duplex Mode",
  2042. X            hdplxflag ? "ON" : "OFF");
  2043. X        return;
  2044. X    }
  2045. X
  2046. X    set_onoff(&hdplxflag);
  2047. X
  2048. X    if (!scriptflag)
  2049. X        sprintf(Msg,"Half-duplex Mode is %s", hdplxflag ? "ON" : "OFF"),
  2050. X        S;
  2051. X}
  2052. X
  2053. static
  2054. SET_menu()
  2055. X{
  2056. X     if (statflag){
  2057. X         fprintf(tfp, statfmt, "menu", "Mini-menu mode",
  2058. X             menuflag ? "ON" : "OFF");
  2059. X         return;
  2060. X    }
  2061. X     set_onoff(&menuflag);
  2062. X     if (!scriptflag)
  2063. X         sprintf(Msg,"Mini-menu is %s shown", menuflag ? "" : "NOT"),
  2064. X        S;
  2065. X}
  2066. X
  2067. static
  2068. SET_autocapt()
  2069. X{
  2070. X    if (statflag){
  2071. X        fprintf(tfp, statfmt, "auto", "Auto Capture",
  2072. X            autoflag ? "ON" : "OFF");
  2073. X        return;
  2074. X    }
  2075. X
  2076. X    set_onoff(&autoflag);
  2077. X
  2078. X    if (!scriptflag)
  2079. X        sprintf(Msg,"Auto Capture is %s", autoflag ? "ON" : "OFF"),
  2080. X        S;
  2081. X}
  2082. X
  2083. static
  2084. SET_cfile()
  2085. X{
  2086. X    if (statflag){
  2087. X        fprintf(tfp, statfmt, "cfile", "Capture File", captfile);
  2088. X        return;
  2089. X    }
  2090. X
  2091. X    getword();
  2092. X    if (word[0] == '\0'){
  2093. X        S1("Set CFILE must have file name");
  2094. X        eofflag++;
  2095. X        return;
  2096. X    }
  2097. X
  2098. X    strcpy(captfile, word);
  2099. X
  2100. X    if (!scriptflag)
  2101. X        sprintf(Msg,"Capture file set to '%s'",captfile),
  2102. X        S;
  2103. X}
  2104. X
  2105. static
  2106. SET_pfile()
  2107. X{
  2108. X    if (statflag){
  2109. X        fprintf(tfp, statfmt, "pfile", "Phone Number File", phonefile);
  2110. X        return;
  2111. X    }
  2112. X
  2113. X    getword();
  2114. X    if (word[0] == '\0'){
  2115. X        S1("Set PFILE must have file name");
  2116. X        eofflag++;
  2117. X        return;
  2118. X    }
  2119. X
  2120. X    strcpy(phonefile, word);
  2121. X
  2122. X    if (!scriptflag)
  2123. X        sprintf(Msg,"Phone number file set to '%s'",phonefile),
  2124. X        S;
  2125. X}
  2126. X
  2127. X/*    Put and Take a file to/from a UNIX-type "cu" system. Unfortunately,
  2128. X    the stty command is one of those commands that always gets changed
  2129. X    with different UNIX systems, so you will get (at least) a file full of
  2130. X    ^M on the take command for systems later than V7 or work-alikes.
  2131. X
  2132. X    Additionally, the Take command takes a bit too much!
  2133. X
  2134. X    Fixed a lot of this: JPRadley 89/07/27
  2135. X*/
  2136. X
  2137. static
  2138. puttake()
  2139. X{
  2140. X    FILE *fp;
  2141. X    int i, Ch;
  2142. X    char c = word[1], fname[SM_BUFF], tname[SM_BUFF], wrkbuf[SM_BUFF];
  2143. X
  2144. X    getword();
  2145. X
  2146. X    signal(SIGINT,catch);
  2147. X    signal(SIGQUIT,catch);
  2148. X    xc_setflow(TRUE);
  2149. X    if (word[0] == '\0'){
  2150. X        sprintf(Msg,"Must give a filename with the '%%%c' option",c);
  2151. X        S;
  2152. X        return;
  2153. X    }
  2154. X
  2155. X    strcpy(fname, word);
  2156. X    getword();
  2157. X    if (word[0] == '\0')
  2158. X        strcpy(tname, fname);
  2159. X    else
  2160. X        strcpy(tname, word);
  2161. X    switch (c){
  2162. X    case 'p':
  2163. X        if (!(fp = fopen(fname, "r")))
  2164. X            sprintf(Msg,"Can't open '%s'",fname),
  2165. X            S;
  2166. X        else {
  2167. X            fprintf(tfp, "\r\nPutting file '%s' to '%s' on remote UNIX\r\n",
  2168. X                fname, tname);
  2169. X            sprintf(wrkbuf,
  2170. X                "sh -c \"stty -echo;(cat >%s)||cat >/dev/null;stty echo\"\n",
  2171. X                    tname);
  2172. X            send_string(wrkbuf);    /* send command string to remote shell */
  2173. X            i = 64;
  2174. X            while ((Ch = getc(fp)) != EOF){
  2175. X                if (++i > 64){        /* this prevents an overload on the */
  2176. X                    i = 0;            /* receiver's input buffer (64=kludge) */
  2177. X                    msecs((1+CBAUD-cbaud) * 100);
  2178. X                }
  2179. X                sendbyte(Ch);        /* send characters to cat command */
  2180. X            }
  2181. X            fclose(fp);
  2182. X            sendbyte(EOT);            /* send a ^D to cat */
  2183. X            purge();                /* get rid of whatever was sent back */
  2184. X            sendbyte('\n');
  2185. X        }
  2186. X        break;
  2187. X
  2188. X    case 't':
  2189. X        strcpy(Name, tname);
  2190. X        if ((fp=QueryCreate(Resume_Not_Allowed))){
  2191. X            fprintf(tfp, "\r\nTaking file '%s' from remote UNIX to '%s'\r\n",
  2192. X                fname, tname);    
  2193. X            purge();
  2194. X            sprintf(wrkbuf,
  2195. X                "sh -c \"stty nl;test -r %s&&cat %s;echo %c;stty -nl\"\n",
  2196. X                    fname, fname, DLE);    /* if 'fname' has a DLE, we'll die */
  2197. X            send_string(wrkbuf);        /* send command to remote shell */
  2198. X            while (readbyte(3) != '\n')    /* discard up to the \n in wrkbuf */
  2199. X                ;
  2200. X            while ((Ch=readbyte(0)) != -1    /* while chars are being sent */
  2201. X                     && Ch != DLE)            /* and we haven't seen our DLE */
  2202. X                fputc(Ch,fp);
  2203. X            fclose(fp);
  2204. X        }
  2205. X        break;
  2206. X    }
  2207. X    xc_setflow(flowflag);
  2208. X    reterm = TRUE;
  2209. X}
  2210. X
  2211. s_exit()
  2212. X{
  2213. X    signal(SIGHUP,SIG_IGN);
  2214. X    signal(SIGINT,SIG_IGN);
  2215. X    signal(SIGQUIT,SIG_IGN);
  2216. X    signal(SIGTERM,SIG_IGN);
  2217. X
  2218. X    mode(OLDMODE);
  2219. X    unlock_tty();
  2220. X
  2221. X    exit(0);
  2222. X}
  2223. END_OF_FILE
  2224. if test 17053 -ne `wc -c <'xcmain.c'`; then
  2225.     echo shar: \"'xcmain.c'\" unpacked with wrong size!
  2226. fi
  2227. # end of 'xcmain.c'
  2228. fi
  2229. if test -f 'xcport.c' -a "${1}" != "-c" ; then 
  2230.   echo shar: Will not clobber existing file \"'xcport.c'\"
  2231. else
  2232. echo shar: Extracting \"'xcport.c'\" \(11658 characters\)
  2233. sed "s/^X//" >'xcport.c' <<'END_OF_FILE'
  2234. X/*    xcport.c -- modem interface routines for XC
  2235. X    This file uses 4-character tabstops
  2236. X*/
  2237. X
  2238. X#include <stdio.h>
  2239. X#include <string.h>
  2240. X#include <sys/types.h>
  2241. X#include <fcntl.h>
  2242. X#include <signal.h>
  2243. X#include <termio.h>
  2244. X#include <sys/ioctl.h>
  2245. X#include <errno.h>
  2246. X#include "xc.h"
  2247. X
  2248. X/* define this if you need to send SIGUSR1/SIGUSR2 to
  2249. X   handle an active getty process, or use ungetty.
  2250. X*/
  2251. X/*#define GETTY_HANDLER /**/
  2252. X
  2253. X# if DIDO == 2            /* SCO Xenix 2.2 uses ungetty */
  2254. X#    define UNGETTY "/usr/lib/uucp/ungetty"
  2255. X#    define UG_NOTENAB    0
  2256. X#    define UG_ENAB        1
  2257. X#    define UG_FAIL        2
  2258. X#    define LOCKDIR "/usr/spool/uucp"
  2259. X#    define SIZEOFLOCKFILE sizeof(short)
  2260. X    static    int    code, retcode, errflag;
  2261. X#    ifndef GETTY_HANDLER
  2262. X#        define GETTY_HANDLER
  2263. X#    endif
  2264. X# endif /*DIDO==2*/
  2265. X
  2266. X# if DIDO == 3            /* SCO Xenix 2.3, SCO Unix */
  2267. X#    include <utmp.h>
  2268. X#    define LOCKDIR "/usr/spool/uucp"
  2269. X#    ifndef ASCII_PID
  2270. X#     define ASCII_PID
  2271. X#     define PIDSIZE 10
  2272. X#    endif
  2273. X    static pid_t gettypid = -1;
  2274. X# endif /*DIDO==3*/
  2275. X
  2276. X# if DIDO == 4            /* System V Release 4 */
  2277. X#    include <utmp.h>
  2278. X#    include <sys/stat.h>
  2279. X#    include <sys/mkdev.h>
  2280. X#    define LOCKDIR "/var/spool/locks"
  2281. X#    ifndef ASCII_PID
  2282. X#     define ASCII_PID
  2283. X#     define PIDSIZE 10
  2284. X#    endif
  2285. X    static pid_t gettypid = -1;
  2286. X# endif /*DIDO==4*/
  2287. X
  2288. X#ifndef SIZEOFLOCKFILE
  2289. X#define SIZEOFLOCKFILE sizeof(int)
  2290. X#endif
  2291. X
  2292. static pid_t pid;
  2293. int cbaud = B2400;            /* default bps */
  2294. short flowflag;                /* modem port i/o data mask */
  2295. static int mfd = -1;        /* modem port file descriptor */
  2296. static struct termio pmode;    /* modem device control string */
  2297. static char port[SM_BUFF],    /* modem port device file string */
  2298. X        lckname[SM_BUFF];    /* lockfile string */
  2299. unsigned mrate ();
  2300. char protocol[] = "8N1";    /* default modem protocol */
  2301. extern int errno;
  2302. X
  2303. struct {
  2304. X    char *proto;
  2305. X    int  clear;
  2306. X    int  set;
  2307. X} prot_tbl[] = {
  2308. X    "8N1",        ~(CSIZE | PARENB | CSTOPB),    CS8,
  2309. X    "7E2",        ~(CSIZE | PARODD),            CS7 | PARENB | CSTOPB,
  2310. X    "7O2",        ~CSIZE,                        CS7 | PARENB | PARODD | CSTOPB,
  2311. X    NIL(char),    0,                            0
  2312. X};
  2313. X
  2314. struct {
  2315. X    char     *bps;
  2316. X    unsigned rate;
  2317. X    int         cbaud;
  2318. X} bps_tbl[] = {
  2319. X    "300",    300,    B300,
  2320. X    "600",    600,    B600,
  2321. X    "1200",    1200,    B1200,
  2322. X    "2400",    2400,    B2400,
  2323. X    "4800",    4800,    B4800,
  2324. X    "9600",    9600,    B9600,
  2325. X#ifdef B19200
  2326. X    "19200",19200,    B19200,
  2327. X#endif
  2328. X#ifdef B38400
  2329. X    "38400",38400,    B38400,
  2330. X    "57600",57600,    B50,
  2331. X#endif
  2332. X    "0",    0,        B0
  2333. X};
  2334. X
  2335. void
  2336. xc_setflow(flow)
  2337. short flow;
  2338. X{
  2339. X    if (flow)
  2340. X        pmode.c_iflag |= IXON | IXOFF | IXANY;
  2341. X    else
  2342. X        pmode.c_iflag &= ~(IXON | IXOFF | IXANY);
  2343. X
  2344. X    ioctl(mfd, TCSETAF, &pmode);
  2345. X}
  2346. X
  2347. X/* get/set character size and parity on the port */
  2348. char *
  2349. xc_setproto(p)
  2350. char *p;
  2351. X{
  2352. X    register i;
  2353. X
  2354. X    if (!p)
  2355. X        return protocol;
  2356. X
  2357. X    for (i=0; prot_tbl[i].proto; i++){
  2358. X        if (!strcmp(p,prot_tbl[i].proto)){
  2359. X            pmode.c_cflag &= prot_tbl[i].clear;
  2360. X            pmode.c_cflag |= prot_tbl[i].set;
  2361. X            ioctl(mfd, TCSETAF, &pmode);
  2362. X            strcpy(protocol,p);
  2363. X            return protocol;
  2364. X        }
  2365. X    }
  2366. X    return NIL(char);
  2367. X}
  2368. X
  2369. X/* get/set port string */
  2370. char *
  2371. mport(s)
  2372. char *s;
  2373. X{
  2374. X    if (s && mfd == -1)
  2375. X        if (strncmp("/dev/", s, 5))
  2376. X            strcpy(port, "/dev/"),
  2377. X            strcat(port, s);
  2378. X        else
  2379. X            strcpy(port, s);
  2380. X
  2381. X    return(port);
  2382. X}
  2383. X
  2384. X/*    Get/set the bps of the modem port; set the terminal rate to correspond. */
  2385. unsigned
  2386. mrate(s)
  2387. char *s;
  2388. X{
  2389. X    register i;
  2390. X
  2391. X    if (s){
  2392. X        for (i=0; bps_tbl[i].cbaud; i++){
  2393. X            if (!strcmp(s,bps_tbl[i].bps)){
  2394. X                cbaud = bps_tbl[i].cbaud;
  2395. X                pmode.c_cflag &= ~CBAUD;
  2396. X                pmode.c_cflag |= cbaud;
  2397. X                ioctl(mfd, TCSETAF, &pmode);
  2398. X                return (bps_tbl[i].rate);
  2399. X            }
  2400. X        }
  2401. X        return FAILURE;
  2402. X    }
  2403. X
  2404. X    for (i=0; bps_tbl[i].cbaud; i++)
  2405. X        if ((pmode.c_cflag & CBAUD) == bps_tbl[i].cbaud)
  2406. X            return (bps_tbl[i].rate);
  2407. X        
  2408. X    return FAILURE;
  2409. X}
  2410. X
  2411. X/*    The following routine is used to hang up the modem. This is accomplished
  2412. X    by setting bps to 0. According to my documentation on termio, setting bps
  2413. X    to zero will result in DTR not being asserted. This hangs up some (most?)
  2414. X    modems. If not, the second part of the routine sends the Hayes modem
  2415. X    "escape" and then a hangup command.
  2416. X*/
  2417. hangup()
  2418. X{
  2419. X    S1("<< HANGUP >>");
  2420. X
  2421. X#if DTR_DROPS_CARRIER
  2422. X    pmode.c_cflag &= ~CBAUD;
  2423. X    pmode.c_cflag |= B0;        /* set cbaud 0 (drop DTR) */
  2424. X    ioctl(mfd, TCSETAF, &pmode);
  2425. X
  2426. X    sleep(1);                    /* wait a second */
  2427. X
  2428. X    pmode.c_cflag &= ~CBAUD;    /* reset bps */
  2429. X    pmode.c_cflag |= cbaud;
  2430. X    ioctl(mfd, TCSETAF, &pmode);
  2431. X#else /* use Hayes command */
  2432. X    sleep(2);                    /* Allow for "escape guard time" */
  2433. X    send_string(ATTEN);            /* Send modem escape command */
  2434. X    sleep(3);                    /* More "escape guard time" */
  2435. X    send_string(HANGUP);        /* Send hangup command */
  2436. X#endif
  2437. X    return SUCCESS;
  2438. X}
  2439. X
  2440. X#ifdef GETTY_HANDLER
  2441. X# if DIDO >= 2
  2442. X/*    suspend() sends signal to a running getty
  2443. X             sets:    gettypid, process number of running getty, if DIDO > 2
  2444. X                    retcode, exit value of 'ungetty', if DIDO = 2
  2445. X    restart(): restarts getty if it had been running before
  2446. X*/
  2447. X#  if DIDO >= 3
  2448. static void
  2449. suspend()
  2450. X{
  2451. X    struct    utmp *t, *getutent();
  2452. X    char buf[12];
  2453. X    void endutent();
  2454. X
  2455. X    strcpy(buf, strrchr(port, '/') +1);
  2456. X    while ((t = getutent())){
  2457. X        if (t->ut_type == LOGIN_PROCESS && (!strcmp(buf, t->ut_line))){
  2458. X            gettypid = t->ut_pid;    /* get getty PID */
  2459. X            if (kill(gettypid, SIGUSR1) == -1 && errno != EPERM)
  2460. X                S1("Can't signal getty");
  2461. X        }
  2462. X    }
  2463. X    endutent();
  2464. X}
  2465. X
  2466. static void
  2467. restart()
  2468. X{
  2469. X    if (gettypid != -1)
  2470. X        kill(gettypid, SIGUSR2);
  2471. X}
  2472. X#  endif /*DIDO>=3*/
  2473. X#  if DIDO == 2
  2474. static void
  2475. suspend()
  2476. X{
  2477. X    code=errflag=pid=retcode=0;
  2478. X    if ((pid = fork()) == 0){
  2479. X        execl(UNGETTY, "ungetty", port, NIL(char));
  2480. X        S1("ungetty exec error");
  2481. X        exit(8);
  2482. X        }
  2483. X    while (((code = wait(&errflag)) != pid) && code != -1);
  2484. X    switch ((errflag>>8) & 0xff){
  2485. X    case UG_NOTENAB:    /* line acquired: not enabled */
  2486. X        retcode = UG_NOTENAB;
  2487. X        break;
  2488. X    case UG_ENAB:    /* line acquired: need ungetty -r when done */
  2489. X        retcode = UG_ENAB;
  2490. X        break;
  2491. X    case UG_FAIL:        /* could not acquire line */
  2492. X    case 255:
  2493. X        exit(8);
  2494. X    }
  2495. X}
  2496. X
  2497. static void
  2498. restart()
  2499. X{
  2500. X    code=errflag=pid=0;
  2501. X    if(retcode == UG_ENAB){
  2502. X        if ((pid = fork()) == 0){
  2503. X            execl(UNGETTY, "ungetty", "-r", port, NIL(char));
  2504. X            exit(8);
  2505. X        }
  2506. X    while (((code = wait(&errflag)) != pid) && code != -1)
  2507. X        ;
  2508. X    }
  2509. X}
  2510. X#  endif /*DIDO==2*/
  2511. X# endif /*DIDO>=2*/
  2512. X#endif /*GETTY_HANDLER*/
  2513. X
  2514. X/*    Attach standard input and output to the modem port. This only gets called
  2515. X    after a fork by the child process, which then exec's a program that uses
  2516. X    standard i/o for some data transfer protocol. (To put this here is actually
  2517. X    a kludge, but I wanted to keep the modem-specific stuff in a black box.)
  2518. X*/
  2519. void
  2520. mattach()
  2521. X{
  2522. X    dup2(mfd, 0);    /* close local stdin and connect to port */
  2523. X    dup2(mfd, 1);    /* close local stdout and connect to port */
  2524. X
  2525. X    close(mfd);        /* close the old port descriptor */
  2526. X}
  2527. X
  2528. static void
  2529. alrm(junk)
  2530. int junk;
  2531. X{ /* do nothing */
  2532. X}
  2533. X
  2534. X/*    Get a byte from the modem port within 'seconds' or return -1.
  2535. X    All data read from the modem are input through this routine.
  2536. X*/
  2537. readbyte(seconds)
  2538. unsigned seconds;
  2539. X{
  2540. X    static int count = 0;
  2541. X    static char *p, rxbuf[SM_BUFF];
  2542. X    unsigned alarm();
  2543. X
  2544. X    if (count > 0){
  2545. X        count--;
  2546. X        return(*p++ & 0xff);
  2547. X    }
  2548. X    if (seconds){
  2549. X        signal(SIGALRM, alrm);
  2550. X        alarm(seconds);
  2551. X    }
  2552. X    if ((count = read(mfd, p = rxbuf, SM_BUFF)) < 1)
  2553. X        return(-1);
  2554. X    if (seconds)
  2555. X        alarm(0);
  2556. X
  2557. X    count--;
  2558. X    return(*p++ & 0xff);
  2559. X}
  2560. X
  2561. X/*    Output a byte to the modem port.
  2562. X    All data sent to the modem are output through this routine.
  2563. X*/
  2564. void
  2565. sendbyte(ch)
  2566. int ch;
  2567. X{
  2568. X    char c = ch & 0xff;
  2569. X
  2570. X    if(write(mfd, &c, 1)<0)
  2571. X        S1("sendbyte: write error!");
  2572. X}
  2573. X
  2574. void
  2575. send_string(s)
  2576. char *s;
  2577. X{
  2578. X    while (*s){
  2579. X        sendbyte(*s++);
  2580. X        /* msecs(35);         /* season to taste ... */
  2581. X    }
  2582. X}
  2583. X
  2584. X/* send a modem break */
  2585. xmitbrk()
  2586. X{
  2587. X    S1("<< BREAK >>");
  2588. X    ioctl(mfd, TCSBRK, 0);
  2589. X    return SUCCESS;
  2590. X}
  2591. X
  2592. X/*    lock_tty() returns FAILURE if the lock file exists (and XC will not run).
  2593. X
  2594. X    unlock_tty() deletes the lock file.
  2595. X
  2596. X    SCOXENIX 2.3 mods: Steve Manes
  2597. X    Check for active LCK file and try to delete it
  2598. X
  2599. X    SCOXENIX 2.2 mods: Jean-Pierre Radley
  2600. X    As above, using 'ungetty'
  2601. X
  2602. X    Tandy 6000 mods: Fred Buck
  2603. X      SVR4 mods: Larry Rosenman
  2604. X*/
  2605. X
  2606. static
  2607. lock_tty()
  2608. X{
  2609. X#if DIDO >= 2
  2610. X    int lckfd;
  2611. X    char *s, buf[12];
  2612. X#ifdef ASCII_PID
  2613. X    static char apid[PIDSIZE+2] = { '\0' };
  2614. X#else
  2615. X    pid = -1;
  2616. X#endif
  2617. X
  2618. X    strcpy(buf, strrchr(port, '/') +1);
  2619. X    s = buf + strlen(buf) - 1;
  2620. X
  2621. X#if DIDO == 2
  2622. X    *s = toupper(*s);
  2623. X#endif
  2624. X#if DIDO >= 3
  2625. X    *s = tolower(*s);
  2626. X#endif
  2627. X
  2628. X#if DIDO == 4
  2629. X    struct stat stat_buf;
  2630. X    if(stat(port,&stat_buf)==0){
  2631. X        sprintf(lckname,"%s/LK.%03d.%03d.%03d",LOCKDIR,
  2632. X            major(stat_buf.st_dev),
  2633. X            major(stat_buf.st_rdev),
  2634. X            minor(stat_buf.st_rdev));
  2635. X    }
  2636. X#else
  2637. X    sprintf(lckname, "%s/LCK..%s", LOCKDIR, buf);
  2638. X#endif  /*DIDO==4*/
  2639. X
  2640. X    if (!checkLCK())    /* check LCK file */
  2641. X        return FAILURE;    /* can't unlock it */
  2642. X
  2643. X    if ((lckfd = creat(lckname, 0666)) < 0){
  2644. X        sprintf(Msg,"Can't create '%s'", lckname);
  2645. X        S;
  2646. X        return FAILURE;
  2647. X    }
  2648. X
  2649. X#ifdef ASCII_PID
  2650. X    sprintf(apid, "%*d\n", PIDSIZE, getpid());
  2651. X    write(lckfd, apid, PIDSIZE+1);
  2652. X#else
  2653. X    pid = getpid();
  2654. X    write(lckfd, (char *)&pid, SIZEOFLOCKFILE);
  2655. X#endif
  2656. X
  2657. X    close(lckfd);
  2658. X#endif /*DIDO*/
  2659. X    return SUCCESS;
  2660. X}
  2661. X
  2662. void
  2663. unlock_tty()
  2664. X{
  2665. X    static char byettyxx[50], *byeptr;
  2666. X    extern char *ttyname();
  2667. X
  2668. X    sprintf(byettyxx,"BYE%s", strrchr(ttyname(mfd),'/')+1);
  2669. X    byeptr = getenv(byettyxx);
  2670. X    if (byeptr && *byeptr)
  2671. X        S1("Sending BYE string to modem"),
  2672. X        send_string("\r"),
  2673. X        send_string(byeptr),
  2674. X        send_string("\r");
  2675. X
  2676. X    pmode.c_cflag &= ~CLOCAL;
  2677. X    pmode.c_cflag |= B0 | HUPCL;
  2678. X    ioctl(mfd, TCSETAF, &pmode);
  2679. X    close(mfd);
  2680. X
  2681. X#if DIDO >= 2
  2682. X    setuid(geteuid());
  2683. X    setgid(getegid());
  2684. X    unlink(lckname);
  2685. X# ifdef GETTY_HANDLER
  2686. X    restart();
  2687. X# endif
  2688. X#endif
  2689. X    S1("Exiting XC");
  2690. X}
  2691. X
  2692. X/*    check to see if lock file exists and is still active.
  2693. X    kill(pid, 0) only works on ATTSV, some BSDs and Xenix
  2694. X    returns: SUCCESS, or
  2695. X            FAILURE if lock file active
  2696. X    added: Steve Manes 7/29/88
  2697. X*/
  2698. checkLCK()
  2699. X{
  2700. X    int rc, fd;
  2701. X#ifdef ASCII_PID
  2702. X    char alckpid[PIDSIZE+2];
  2703. X#endif
  2704. X#if DIDO == 2
  2705. X    short lckpid = -1;
  2706. X#else
  2707. X    pid_t lckpid = -1;
  2708. X#endif
  2709. X
  2710. X    if ((fd = open(lckname, O_RDONLY)) == -1){
  2711. X        if (errno == ENOENT)
  2712. X            return SUCCESS;    /* lock file doesn't exist */
  2713. X        goto unlock;
  2714. X    }
  2715. X#ifdef ASCII_PID
  2716. X    rc = read(fd, (char *)alckpid, PIDSIZE+1);
  2717. X    close(fd);
  2718. X    lckpid = atoi(alckpid);
  2719. X    if (rc != 11)
  2720. X#else
  2721. X    rc = read(fd, (char *)&lckpid, SIZEOFLOCKFILE);
  2722. X    close(fd);
  2723. X    if (rc != SIZEOFLOCKFILE)
  2724. X#endif
  2725. X    {
  2726. X        S1("Lock file has bad format");
  2727. X        goto unlock;
  2728. X    }
  2729. X
  2730. X    /* now, send a bogus 'kill' and check the results */
  2731. X    if (kill(lckpid, 0) == 0 || errno == EPERM){
  2732. X        sprintf(Msg,"Lock file process %d on %s is still active - try later",
  2733. X            lckpid, port);
  2734. X        S;
  2735. X        return FAILURE;
  2736. X    }
  2737. X
  2738. unlock:
  2739. X    if (unlink(lckname) != 0){
  2740. X        sprintf(Msg,"Can't unlink %s file", lckname);
  2741. X        S;
  2742. X        return FAILURE;
  2743. X    }
  2744. X    return SUCCESS;
  2745. X}
  2746. X
  2747. X/*    Opens the modem port and configures it. If the port string is
  2748. X    already defined it will use that as the modem port; otherwise it
  2749. X    gets the environment variable MODEM. Returns SUCCESS or FAILURE.
  2750. X*/
  2751. mopen()
  2752. X{
  2753. X    int c;
  2754. X    char *p;
  2755. X
  2756. X    if (port[0] == '\0'){
  2757. X        if (!(p = getenv("MODEM"))){
  2758. X            S1("Exiting: no modem port specified or present in environment");
  2759. X            exit(3);
  2760. X        }
  2761. X        mport(p);
  2762. X    }
  2763. X    if (!lock_tty())
  2764. X        exit(4);
  2765. X
  2766. X#if DIDO
  2767. X    p = port +strlen(port) -1;
  2768. X    *p = toupper(*p);
  2769. X# ifdef GETTY_HANDLER
  2770. X    suspend();
  2771. X# endif
  2772. X#endif
  2773. X
  2774. X    if ((mfd = open(port, O_RDWR | O_NDELAY)) < 0){
  2775. X        sprintf(Msg,"Can't open modem port %s",port);
  2776. X        S;
  2777. X        exit(5);
  2778. X    }
  2779. X
  2780. X    ioctl(mfd, TCGETA, &pmode);
  2781. X
  2782. X    pmode.c_cflag &= ~(CBAUD | HUPCL);
  2783. X    pmode.c_cflag |= CLOCAL | cbaud;
  2784. X#if DIDO >= 3 & defined(CTSFLOW) & defined(RTSFLOW)
  2785. X    pmode.c_cflag |= CTSFLOW | RTSFLOW ;
  2786. X    /* pmode.c_cflag |= CRTSFL ; */
  2787. X#endif
  2788. X    pmode.c_iflag = IGNBRK ;
  2789. X    pmode.c_oflag = pmode.c_lflag = 0;
  2790. X    pmode.c_cc[VMIN] = 1;     /* This many chars satisfies reads */
  2791. X    pmode.c_cc[VTIME] = 0;    /* or in this many tenths of seconds */
  2792. X
  2793. X    xc_setflow(flowflag);
  2794. X
  2795. X    c = mfd;
  2796. X    if ((mfd = open(port, O_RDWR)) < 0){    /* Reopen line with CLOCAL */
  2797. X        sprintf(Msg,"Can't re-open modem port %s",port);
  2798. X        S;
  2799. X        return FAILURE;
  2800. X    }
  2801. X    close(c);
  2802. X
  2803. X    return SUCCESS;
  2804. X}
  2805. END_OF_FILE
  2806. if test 11658 -ne `wc -c <'xcport.c'`; then
  2807.     echo shar: \"'xcport.c'\" unpacked with wrong size!
  2808. fi
  2809. # end of 'xcport.c'
  2810. fi
  2811. if test -f 'xcxmdm.c' -a "${1}" != "-c" ; then 
  2812.   echo shar: Will not clobber existing file \"'xcxmdm.c'\"
  2813. else
  2814. echo shar: Extracting \"'xcxmdm.c'\" \(10779 characters\)
  2815. sed "s/^X//" >'xcxmdm.c' <<'END_OF_FILE'
  2816. X/*    xcxmdm.c -- XMODEM Protocol module for XC
  2817. X    This file uses 4-character tabstops
  2818. X*/
  2819. X
  2820. X#include <stdio.h>
  2821. X#include <string.h>
  2822. X#include <sys/types.h>
  2823. X#include <sys/stat.h>
  2824. X#include <signal.h>
  2825. X#include <setjmp.h>
  2826. X#include "xc.h"
  2827. X
  2828. X#define CPMEOF    032    /* ^Z */
  2829. X#define WANTCRC 'C'
  2830. X#define OK         0
  2831. X#define TIMEOUT    -1     /* -1 is returned by readbyte() upon timeout */
  2832. X#define ERROR    -2
  2833. X#define WCEOT    -3
  2834. X#define RETRYMAX 10
  2835. X#define SECSIZ  128
  2836. X#define Resume_Not_Allowed    1
  2837. X
  2838. X/* crc_xmodem_tab calculated by Mark G. Mendel, Network Systems Corporation */
  2839. ushort crc_xmodem_tab[256] = {
  2840. X     0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
  2841. X     0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
  2842. X     0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
  2843. X     0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
  2844. X     0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
  2845. X     0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
  2846. X     0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
  2847. X     0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
  2848. X     0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
  2849. X     0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
  2850. X     0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
  2851. X     0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
  2852. X     0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
  2853. X     0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
  2854. X     0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
  2855. X     0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
  2856. X     0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
  2857. X     0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
  2858. X     0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
  2859. X     0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
  2860. X     0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
  2861. X     0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
  2862. X     0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
  2863. X     0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
  2864. X     0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
  2865. X     0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
  2866. X     0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
  2867. X     0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
  2868. X     0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
  2869. X     0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
  2870. X     0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
  2871. X     0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
  2872. X};
  2873. X
  2874. short crcheck = TRUE;        /* CRC check enabled? */
  2875. static FILE *xfp;            /* buffered file pointer */
  2876. static short firstsec,        /* first sector of file or not? */
  2877. X            textmode,        /* Text translations enabled? */
  2878. X            save_crc;        /* Saved crcheck value */
  2879. static char wcbuf[SECSIZ];    /* Ward Christensen sector buffer */
  2880. static ushort Updcrc();
  2881. static jmp_buf our_env;
  2882. static void (*oldvec)();
  2883. X
  2884. X/*    send 10 CAN's to try to get the other end to shut up */
  2885. static void
  2886. canit()
  2887. X{
  2888. X    int i;
  2889. X
  2890. X    for(i = 0; i < 20; i++)
  2891. X        sendbyte(CAN);
  2892. X}
  2893. X
  2894. static void
  2895. xmsigint(junk)
  2896. int junk;
  2897. X{
  2898. X    show_abort();
  2899. X    signal(SIGINT, SIG_IGN);    /* Ignore subsequent DEL's */
  2900. X    canit();                    /* Abort the transmission */
  2901. X    longjmp(our_env,1);
  2902. X}
  2903. X
  2904. X/*    fill the CP/M sector buffer from the UNIX file
  2905. X    do text adjustments if necessary
  2906. X    return 1 if more sectors are to be read, or 0 if this is the last
  2907. X*/
  2908. static
  2909. getsec()
  2910. X{
  2911. X    int i;
  2912. X    register c;
  2913. X
  2914. X    i = 0;
  2915. X    while(i < SECSIZ && (c = getc(xfp)) != EOF){
  2916. X        if (textmode && c == '\n'){
  2917. X            wcbuf[i++] = '\r';
  2918. X            if (i >= SECSIZ){         /* handle a newline on the last byte */
  2919. X                ungetc(c, xfp);         /* of the sector */
  2920. X                return(1);
  2921. X            }
  2922. X        }
  2923. X        wcbuf[i++] = c;
  2924. X    }
  2925. X    /* make sure that an extra blank sector is not sent */
  2926. X    if (c != EOF && (c = getc(xfp)) != EOF){
  2927. X        ungetc(c, xfp);
  2928. X        return(1);
  2929. X    }
  2930. X    /* fill up the last sector with ^Z's if text mode or 0's if binary mode */
  2931. X    while(i < SECSIZ)
  2932. X        wcbuf[i++] = textmode ? CPMEOF : '\0';
  2933. X    return(0);
  2934. X}
  2935. X
  2936. X/*    wcgetsec() inputs an XMODEM "sector".
  2937. X    This routine returns the sector number encountered, or ERROR if a valid
  2938. X    sector is not received or CAN received; or WCEOT if EOT sector.
  2939. X
  2940. X    Maxtime is the timeout for the first character, set to 6 seconds for
  2941. X    retries. No ACK is sent if the sector is received ok. This must be
  2942. X    done by the caller when it is ready to receive the next sector.
  2943. X*/
  2944. static
  2945. wcgetsec(maxtime)
  2946. unsigned maxtime;
  2947. X{
  2948. X    register ushort oldcrc;
  2949. X    register checksum, j, c;
  2950. X    int sectcurr, sectcomp, attempts;
  2951. X
  2952. X    for(attempts = 0; attempts < RETRYMAX; attempts++){
  2953. X        do {
  2954. X            c = readbyte(maxtime);
  2955. X        } while(c != SOH && c != EOT && c != CAN && c != TIMEOUT);
  2956. X
  2957. X        switch(c){
  2958. X        case SOH:
  2959. X            sectcurr = readbyte(3);
  2960. X            sectcomp = readbyte(3);
  2961. X            if ((sectcurr + sectcomp) == 0xff){
  2962. X                oldcrc = checksum = 0;
  2963. X                for(j = 0; j < SECSIZ; j++){
  2964. X                    if ((c = readbyte(3)) == TIMEOUT)
  2965. X                        goto timeout;
  2966. X                    wcbuf[j] = c;
  2967. X                    if (crcheck)
  2968. X                        oldcrc = Updcrc(c, oldcrc);
  2969. X                    else
  2970. X                        checksum += c;
  2971. X                }
  2972. X                if ((c = readbyte(3)) < 0)
  2973. X                    goto timeout;
  2974. X                if (crcheck){
  2975. X                    oldcrc = Updcrc(c, oldcrc);
  2976. X                    if ((c = readbyte(3)) == TIMEOUT)
  2977. X                        goto timeout;
  2978. X                    if (Updcrc(c, oldcrc)){
  2979. X                        S2("CRC error");
  2980. X                        break;
  2981. X                    }
  2982. X                }
  2983. X                else if (((checksum - c) & 0xff) != 0){
  2984. X                    S2("Checksum error");
  2985. X                    break;
  2986. X                }
  2987. X                firstsec = FALSE;
  2988. X                return(sectcurr);
  2989. X            }
  2990. X            else
  2991. X                sprintf(Msg, "Sector number garbled 0%03o 0%03o",
  2992. X                    sectcurr, sectcomp);
  2993. X                S2(Msg);
  2994. X            break;
  2995. X        case EOT:
  2996. X            if (readbyte(3) == TIMEOUT)
  2997. X                return(WCEOT);
  2998. X            break;
  2999. X        case CAN:
  3000. X            S2("Sender CANcelled");
  3001. X            return(ERROR);
  3002. X        case TIMEOUT:
  3003. X            if (firstsec)
  3004. X            break;
  3005. timeout:
  3006. X        S2("Timeout");
  3007. X        break;
  3008. X        }
  3009. X        S2("Trying again on this sector");
  3010. X        purge();
  3011. X        if (firstsec)
  3012. X            sendbyte(crcheck ? WANTCRC : NAK);
  3013. X        else
  3014. X            maxtime = 6,
  3015. X            sendbyte(NAK);
  3016. X    }
  3017. X    S2("Retry count exceeded");
  3018. X    canit();
  3019. X    return(ERROR);
  3020. X}
  3021. X
  3022. static
  3023. putsec()
  3024. X{
  3025. X    int i;
  3026. X    register c;
  3027. X
  3028. X    for(i = 0; i < SECSIZ; i++){
  3029. X        c = wcbuf[i];
  3030. X        if (textmode){
  3031. X            if (c == CPMEOF)
  3032. X                return(1);
  3033. X            if (c == '\r')
  3034. X                continue;
  3035. X        }
  3036. X        putc(c, xfp);
  3037. X    }
  3038. X    return(0);
  3039. X}
  3040. X
  3041. X/* Receive a file using XMODEM protocol */
  3042. static
  3043. wcrx()
  3044. X{
  3045. X    register sendchar, sectnum, sectcurr;
  3046. X
  3047. X    strcpy(Name, word);
  3048. X    if (!(xfp=QueryCreate(Resume_Not_Allowed)))
  3049. X        return(ERROR);
  3050. X
  3051. X    firstsec = TRUE;
  3052. X    sectnum = 0;
  3053. X    sendchar = crcheck ? WANTCRC : NAK;
  3054. X    fputc('\r',tfp),
  3055. X    fputc('\n', tfp);
  3056. X    S1("Sync...");
  3057. X
  3058. X    while(TRUE){
  3059. X        purge();
  3060. X        sendbyte(sendchar);
  3061. X        sectcurr = wcgetsec(6);
  3062. X        if (sectcurr == ((sectnum + 1) & 0xff)){
  3063. X            sectnum++;
  3064. X            putsec();
  3065. X            fprintf(tfp,"Received sector #%d\r", sectnum);
  3066. X            sendchar = ACK;
  3067. X            continue;
  3068. X        }
  3069. X
  3070. X        if (sectcurr == (sectnum & 0xff)){
  3071. X            sprintf(Msg, "Received duplicate sector #%d", sectnum);
  3072. X            S2(Msg);
  3073. X            sendchar = ACK;
  3074. X            continue;
  3075. X        }
  3076. X
  3077. X        fclose(xfp);
  3078. X
  3079. X        if (sectcurr == WCEOT){
  3080. X            S1("File received OK");
  3081. X            sendbyte(ACK);
  3082. X            return(OK);
  3083. X        }
  3084. X
  3085. X        if (sectcurr == ERROR)
  3086. X            return(ERROR);
  3087. X
  3088. X        sprintf(Msg, "Sync error ... expected %d(%d), got %d",
  3089. X            (sectnum + 1) & 0xff, sectnum, sectcurr);
  3090. X        S;
  3091. X        return(ERROR);
  3092. X    }
  3093. X}
  3094. X
  3095. X/*    wcputsec outputs a Ward Christensen type sector.
  3096. X    it returns OK or ERROR
  3097. X*/
  3098. static
  3099. wcputsec(sectnum)
  3100. int sectnum;
  3101. X{
  3102. X    register ushort oldcrc;
  3103. X    register checksum, j, c, attempts;
  3104. X
  3105. X    oldcrc = checksum = 0;
  3106. X    for(j = 0; j < SECSIZ; j++)
  3107. X        c = wcbuf[j],
  3108. X        oldcrc = Updcrc(c, oldcrc),
  3109. X        checksum += c;
  3110. X    oldcrc = Updcrc(0, Updcrc(0, oldcrc));
  3111. X
  3112. X    for(attempts = 0; attempts < RETRYMAX; attempts++){
  3113. X        sendbyte(SOH);
  3114. X        sendbyte(sectnum);
  3115. X        sendbyte(-sectnum - 1);
  3116. X        for(j = 0; j < SECSIZ; j++)
  3117. X            sendbyte(wcbuf[j]);
  3118. X        purge();
  3119. X        if (crcheck){
  3120. X            sendbyte((int) (oldcrc >> 8));
  3121. X            sendbyte((int) oldcrc);
  3122. X        }
  3123. X        else
  3124. X            sendbyte(checksum);
  3125. X        switch(c = readbyte(10)){
  3126. X        case CAN:
  3127. X        S2("Receiver CANcelled");
  3128. X            return(ERROR);
  3129. X        case ACK:
  3130. X            firstsec = FALSE;
  3131. X            return(OK);
  3132. X        case NAK:
  3133. X        S2("Got a NAK on sector acknowledge");
  3134. X            break;
  3135. X        case TIMEOUT:
  3136. X        S2("Timeout on sector acknowledge");
  3137. X            break;
  3138. X        default:
  3139. X            sprintf(Msg, "Got 0%03o for sector acknowledge", c);
  3140. X            S2(Msg);
  3141. X            do {
  3142. X                if ((c = readbyte(3)) == CAN){
  3143. X                    S2("Receiver CANcelled");
  3144. X                    return(ERROR);
  3145. X                }
  3146. X            } while(c != TIMEOUT);
  3147. X            if (firstsec)
  3148. X                crcheck = (c == WANTCRC);
  3149. X            break;
  3150. X        }
  3151. X    }
  3152. X    S2("Retry count exceeded");
  3153. X    return(ERROR);
  3154. X}
  3155. X
  3156. X/* Transmit a file using XMODEM protocol */
  3157. static
  3158. wctx()
  3159. X{
  3160. X    register sectnum, eoflg, c, attempts;
  3161. X
  3162. X    if (!(xfp = fopen(word, "r"))){
  3163. X        sprintf(Msg, "Can't open '%s'", word);
  3164. X        S;
  3165. X        return(ERROR);
  3166. X    }
  3167. X    firstsec = TRUE;
  3168. X    attempts = 0;
  3169. X    S1("Sync...");
  3170. X
  3171. X    while((c = readbyte(30)) != NAK && c != WANTCRC && c != CAN)
  3172. X        if (c == TIMEOUT && ++attempts > RETRYMAX){
  3173. X            S1("Receiver not responding");
  3174. X            fclose(xfp);
  3175. X            return(ERROR);
  3176. X        }
  3177. X    if (c == CAN){
  3178. X        S1("Receiver CANcelled");
  3179. X        fclose(xfp);
  3180. X        return(ERROR);
  3181. X    }
  3182. X    crcheck = (c == WANTCRC);
  3183. X    sprintf(Msg,"%s error checking requested", crcheck ? "CRC-16" : "Checksum");
  3184. X    S;
  3185. X    sectnum = 1;
  3186. X
  3187. X    do {
  3188. X        eoflg = getsec();
  3189. X        fprintf(tfp,"Transmitting sector #%d\r", sectnum);
  3190. X
  3191. X        if (wcputsec(sectnum) == ERROR){
  3192. X            fclose(xfp);
  3193. X            return(ERROR);
  3194. X        }
  3195. X        sectnum++;
  3196. X    } while(eoflg);
  3197. X
  3198. X    fclose(xfp);
  3199. X    attempts = 0;
  3200. X    sendbyte(EOT);
  3201. X    while(readbyte(5) != ACK && attempts++ < RETRYMAX)
  3202. X        sendbyte(EOT);
  3203. X    if (attempts >= RETRYMAX){
  3204. X        S1("Receiver not responding to completion");
  3205. X        return(ERROR);
  3206. X    }
  3207. X
  3208. X    S1("Transmission complete");
  3209. X    return(OK);
  3210. X}
  3211. X
  3212. X/*    update the cyclic redundancy check value */
  3213. static ushort
  3214. Updcrc(c, crc)
  3215. register c;
  3216. register unsigned crc;
  3217. X{
  3218. X    int i;
  3219. X
  3220. X    for(i = 0; i < 8; i++){
  3221. X        if (crc & 0x8000)
  3222. X            crc <<= 1,
  3223. X            crc += (((c <<= 1) & 0400) != 0),
  3224. X            crc ^= 0x1021;
  3225. X        else
  3226. X            crc <<= 1,
  3227. X            crc += (((c <<= 1) & 0400) != 0);
  3228. X    }
  3229. X    return(crc);
  3230. X}
  3231. X
  3232. static
  3233. setmode(c)
  3234. int c;
  3235. X{
  3236. X    switch(tolower(c)){
  3237. X    case 't':
  3238. X        textmode = TRUE;
  3239. X        break;
  3240. X    case 'b':
  3241. X        textmode = FALSE;
  3242. X    case ' ':
  3243. X        break;
  3244. X
  3245. X    default:
  3246. X        return FAILURE;
  3247. X    }
  3248. X
  3249. X    sprintf(Msg, "XMODEM %s file transfer mode", textmode ? "Text" : "Binary");
  3250. X    S;
  3251. X
  3252. X    return SUCCESS;
  3253. X}
  3254. X
  3255. X/*    Put received WC sector into a UNIX file
  3256. X    using text translations if neccesary.
  3257. X*/
  3258. X
  3259. void
  3260. xreceive(c)
  3261. int c;
  3262. X{
  3263. X    save_crc = crcheck;
  3264. X    oldvec = signal(SIGINT, xmsigint);
  3265. X
  3266. X    if (setmode(c)){
  3267. X        if (!setjmp(our_env)){
  3268. X            /* crcheck = 0xff; */
  3269. X
  3270. X            sprintf(Msg, "Ready to receive single file %s", word);
  3271. X            S;
  3272. X            if (wcrx() == ERROR)
  3273. X                canit();
  3274. X            return;
  3275. X        }
  3276. X    }
  3277. X
  3278. X    signal(SIGINT, oldvec);
  3279. X    crcheck = save_crc;
  3280. X}
  3281. X
  3282. void
  3283. xsend(c)
  3284. int c;
  3285. X{
  3286. X    save_crc = crcheck;
  3287. X    oldvec = signal(SIGINT, xmsigint);
  3288. X
  3289. X    if (setmode(c)){
  3290. X        if (!setjmp(our_env)){
  3291. X            /* crcheck = 0xff; */
  3292. X            if (wctx() == ERROR){
  3293. X                sprintf(Msg, "Error transmitting file %s", word);
  3294. X                S;
  3295. X                return;
  3296. X            }
  3297. X        }
  3298. X    }
  3299. X
  3300. X    signal(SIGINT, oldvec);
  3301. X    crcheck = save_crc;
  3302. X}
  3303. END_OF_FILE
  3304. if test 10779 -ne `wc -c <'xcxmdm.c'`; then
  3305.     echo shar: \"'xcxmdm.c'\" unpacked with wrong size!
  3306. fi
  3307. # end of 'xcxmdm.c'
  3308. fi
  3309. echo shar: End of archive 2 \(of 3\).
  3310. cp /dev/null ark2isdone
  3311. MISSING=""
  3312. for I in 1 2 3 ; do
  3313.     if test ! -f ark${I}isdone ; then
  3314.     MISSING="${MISSING} ${I}"
  3315.     fi
  3316. done
  3317. if test "${MISSING}" = "" ; then
  3318.     echo You have unpacked all 3 archives.
  3319.     rm -f ark[1-9]isdone
  3320. else
  3321.     echo You still need to unpack the following archives:
  3322.     echo "        " ${MISSING}
  3323. fi
  3324. ##  End of shell archive.
  3325. exit 0
  3326.